from dataclasses import dataclass

import eth_utils
from eth_account import Account
from eth_account.hdaccount import Mnemonic
from eth_keys import KeyAPI
from eth_typing import ChecksumAddress
from eth_utils import decode_hex

Account.enable_unaudited_hdwallet_features()  # type: ignore[no-untyped-call]

key_api = KeyAPI()


@dataclass
class NewAccount:
    path: str
    address: str
    private_key: str


def to_checksum_address(address: str) -> ChecksumAddress:
    return eth_utils.to_checksum_address(address)


def generate_mnemonic(num_words: int = 24) -> str:
    mnemonic = Mnemonic("english")  # type: ignore[no-untyped-call]
    return mnemonic.generate(num_words=num_words)


def generate_accounts(  # nosec
    mnemonic: str,
    passphrase: str = "",
    path_prefix: str = "m/44'/60'/0'/0",
    limit: int = 12,
) -> list[NewAccount]:
    result: list[NewAccount] = []
    for i in range(limit):
        path = f"{path_prefix}/{i}"
        acc = Account.from_mnemonic(mnemonic=mnemonic, account_path=path, passphrase=passphrase)
        result.append(NewAccount(path, acc.address, acc.key.hex()))
    return result


def private_to_address(private_key: str) -> str | None:
    """returns address in lower case"""
    # noinspection PyBroadException
    try:
        return key_api.PrivateKey(decode_hex(private_key)).public_key.to_address().lower()
    except Exception:
        return None


def create_private_keys_dict(private_keys: list[str]) -> dict[str, str]:  # address in lower
    result = {}
    for private_key in private_keys:
        address = private_to_address(private_key)
        if address is None:
            raise ValueError("wrong private key")
        result[address.lower()] = private_key
    return result


def is_private_key(private_key: str) -> bool:
    # noinspection PyBroadException
    try:
        key_api.PrivateKey(decode_hex(private_key)).public_key.to_address()
        return True
    except Exception:
        return False
