import { HDNodeWallet, Wallet } from "ethers";
import { Keypair } from "@solana/web3.js";
import { derivePath } from "ed25519-hd-key";
import { mnemonicToSeedSync, validateMnemonic } from "bip39";
import { EVM_CHAIN_TYPES, normalizeRequiredChainType } from "./ChainConfig";

export interface GeneratedWallet {
  chain_type: string;
  address: string;
  derivation_path: string;
  index: number;
}

export class WalletGenerationService {
  private readonly mnemonic: string;
  private readonly evmDerivationTemplate: string;
  private readonly solDerivationTemplate: string;

  constructor(
    mnemonic: string | undefined,
    evmDerivationTemplate: string = "m/44'/60'/0'/0/{index}",
    solDerivationTemplate: string = "m/44'/501'/{index}'/0'"
  ) {
    this.mnemonic = String(mnemonic || "").trim();
    this.evmDerivationTemplate = evmDerivationTemplate;
    this.solDerivationTemplate = solDerivationTemplate;

    if (!this.mnemonic) {
      throw new Error("Missing WALLET_ENGINE_MNEMONIC");
    }

    if (!validateMnemonic(this.mnemonic)) {
      throw new Error("WALLET_ENGINE_MNEMONIC is invalid");
    }
  }

  generate(chainType: string, index: number): GeneratedWallet {
    if (!Number.isInteger(index) || index < 0) {
      throw new Error("Wallet derivation index must be a non-negative integer");
    }

    const normalizedChain = this.normalizeChainType(chainType);
    if (normalizedChain === "solana") {
      return this.generateSolana(index);
    }

    if (normalizedChain === "ethereum" || normalizedChain === "base" || normalizedChain === "bsc") {
      return this.generateEvm(normalizedChain, index);
    }

    throw new Error(`Unsupported chain_type '${chainType}' for wallet generation`);
  }

  deriveEvmWallet(chainType: string, index: number): Wallet {
    const normalizedChain = this.normalizeChainType(chainType);
    if (!EVM_CHAIN_TYPES.has(normalizedChain)) {
      throw new Error(`Unsupported chain_type '${chainType}' for EVM signer derivation`);
    }

    const path = this.resolvePath(this.evmDerivationTemplate, index);
    const derived = HDNodeWallet.fromPhrase(this.mnemonic, undefined, path);
    return new Wallet(derived.privateKey);
  }

  deriveSolanaKeypair(index: number): Keypair {
    const path = this.resolvePath(this.solDerivationTemplate, index);
    const seed = mnemonicToSeedSync(this.mnemonic);
    const derived = derivePath(path, seed.toString("hex"));
    return Keypair.fromSeed(derived.key);
  }

  private generateEvm(chainType: string, index: number): GeneratedWallet {
    const path = this.resolvePath(this.evmDerivationTemplate, index);
    const derived = HDNodeWallet.fromPhrase(this.mnemonic, undefined, path);

    return {
      chain_type: chainType,
      address: derived.address,
      derivation_path: path,
      index,
    };
  }

  private generateSolana(index: number): GeneratedWallet {
    const path = this.resolvePath(this.solDerivationTemplate, index);
    const keypair = this.deriveSolanaKeypair(index);

    return {
      chain_type: "solana",
      address: keypair.publicKey.toBase58(),
      derivation_path: path,
      index,
    };
  }

  private resolvePath(template: string, index: number): string {
    return template.replace("{index}", String(index));
  }

  private normalizeChainType(chainType: string): string {
    return normalizeRequiredChainType(chainType);
  }
}
