#!/usr/bin/env python3
import argparse
import json
import subprocess
import sys


def ensure_pip():
    try:
        import pip  # noqa: F401

        return True
    except Exception:
        try:
            import ensurepip

            ensurepip.bootstrap()
            return True
        except Exception:
            return False


def load_bip_utils():
    try:
        from bip_utils import (
            Bip39MnemonicGenerator,
            Bip39WordsNum,
            Bip39SeedGenerator,
            Bip44,
            Bip44Coins,
            Bip44Changes,
        )

        return (
            Bip39MnemonicGenerator,
            Bip39WordsNum,
            Bip39SeedGenerator,
            Bip44,
            Bip44Coins,
            Bip44Changes,
        )
    except Exception:
        if not ensure_pip():
            raise RuntimeError("pip is not available. Install python3-pip first.")
        try:
            subprocess.check_call(
                [sys.executable, "-m", "pip", "install", "--no-cache-dir", "bip-utils"]
            )
        except Exception:
            subprocess.check_call(
                [
                    sys.executable,
                    "-m",
                    "pip",
                    "install",
                    "--no-cache-dir",
                    "--break-system-packages",
                    "bip-utils",
                ]
            )
        from bip_utils import (
            Bip39MnemonicGenerator,
            Bip39WordsNum,
            Bip39SeedGenerator,
            Bip44,
            Bip44Coins,
            Bip44Changes,
        )

        return (
            Bip39MnemonicGenerator,
            Bip39WordsNum,
            Bip39SeedGenerator,
            Bip44,
            Bip44Coins,
            Bip44Changes,
        )


def extract_pubkey_hex(pub_key):
    for attr in ("RawUncompressed", "RawCompressed", "Raw"):
        try:
            raw = getattr(pub_key, attr)()
            return raw.ToHex()
        except Exception:
            continue
    return None


def create_wallet(coin, make_prefix_hex=False):
    (
        Bip39MnemonicGenerator,
        Bip39WordsNum,
        Bip39SeedGenerator,
        Bip44,
        _Bip44Coins,
        Bip44Changes,
    ) = load_bip_utils()
    mnemonic = Bip39MnemonicGenerator().FromWordsNumber(Bip39WordsNum.WORDS_NUM_12)
    seed = Bip39SeedGenerator(mnemonic).Generate()
    ctx = (
        Bip44.FromSeed(seed, coin)
        .Purpose()
        .Coin()
        .Account(0)
        .Change(Bip44Changes.CHAIN_EXT)
        .AddressIndex(0)
    )
    private_key = ctx.PrivateKey().Raw().ToHex()
    public_key = extract_pubkey_hex(ctx.PublicKey())
    address = ctx.PublicKey().ToAddress()
    if public_key is None:
        public_key = address
    if make_prefix_hex:
        if not private_key.startswith("0x"):
            private_key = f"0x{private_key}"
        if public_key and not public_key.startswith("0x"):
            public_key = f"0x{public_key}"
        if address and not address.startswith("0x"):
            address = f"0x{address}"
    return {
        "mnemonic": mnemonic,
        "private_key": private_key,
        "public_key": public_key,
        "address": address,
    }


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--pretty", action="store_true", help="Pretty-print JSON output")
    args = parser.parse_args()

    (
        _Bip39MnemonicGenerator,
        _Bip39WordsNum,
        _Bip39SeedGenerator,
        _Bip44,
        Bip44Coins,
        _Bip44Changes,
    ) = load_bip_utils()

    payload = {
        "evm": create_wallet(Bip44Coins.ETHEREUM, make_prefix_hex=True),
        "solana": create_wallet(Bip44Coins.SOLANA, make_prefix_hex=False),
    }

    if args.pretty:
        print(json.dumps(payload, indent=2))
    else:
        print(json.dumps(payload))


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:
        sys.stderr.write(str(exc) + "\n")
        sys.exit(1)
