/**
 * Node/CommonJS wallet crypto matching web_node/js/wallet_crypto.js (Android parity).
 */
const { sha3_256 } = require("@noble/hashes/sha3");
const { sha256 } = require("@noble/hashes/sha256");
const { ml_dsa87 } = require("@noble/post-quantum/ml-dsa");
const { generateMnemonic, mnemonicToSeedSync, validateMnemonic } = require("@scure/bip39");
const { wordlist } = require("@scure/bip39/wordlists/english");

const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

function bytesToHex(bytes) {
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
}

function concat(a, b) {
  const out = new Uint8Array(a.length + b.length);
  out.set(a, 0);
  out.set(b, a.length);
  return out;
}

function normalizeSeedPhrase(phrase) {
  return String(phrase || "")
    .trim()
    .toLowerCase()
    .replace(/\s+/g, " ");
}

function isValidSeedPhrase(phrase) {
  try {
    return validateMnemonic(normalizeSeedPhrase(phrase), wordlist);
  } catch {
    return false;
  }
}

function createMnemonic() {
  return normalizeSeedPhrase(generateMnemonic(wordlist, 256));
}

function bip39Seed(phrase) {
  return mnemonicToSeedSync(normalizeSeedPhrase(phrase), "");
}

function deriveFullSeed(bipSeed, index = 0) {
  const label = new TextEncoder().encode(`sarmad-wallet-${index}`);
  const label1 = new TextEncoder().encode(`sarmad-wallet-${index}-1`);
  const a = sha256(concat(bipSeed, label));
  const b = sha256(concat(bipSeed, label1));
  const out = new Uint8Array(64);
  out.set(a, 0);
  out.set(b, 32);
  return out;
}

function generateKeyPairFromSeed(fullSeed) {
  const seedBytes = sha3_256(fullSeed);
  const keys = ml_dsa87.keygen(seedBytes);
  return {
    publicKey: keys.publicKey,
    privateKey: keys.secretKey,
    publicKeyHex: bytesToHex(keys.publicKey),
  };
}

function base58Encode(input) {
  if (!input.length) return "";
  const bytes = Uint8Array.from(input);
  let count = 0;
  for (const b of bytes) {
    if (b === 0) count++;
    else break;
  }
  const temp = new Uint8Array(bytes.length * 2);
  let j = temp.length;
  let startAt = count;
  while (startAt < bytes.length) {
    let carry = bytes[startAt];
    let i = 0;
    let k = temp.length - 1;
    while (k >= 0 && (carry !== 0 || i < j - (temp.length - bytes.length))) {
      carry += 256 * temp[k];
      temp[k] = carry % 58;
      carry = (carry / 58) | 0;
      k--;
      i++;
    }
    startAt++;
  }
  let result = "";
  for (const b of temp) {
    if (b !== 0 || result.length) result += ALPHABET[b];
  }
  for (let i = 0; i < count; i++) result = ALPHABET[0] + result;
  return result;
}

function publicKeyToAddress(publicKey) {
  return "SRMD" + base58Encode(sha3_256(publicKey));
}

function sign(data, secretKey) {
  return ml_dsa87.sign(secretKey, data);
}

function verify(data, signature, publicKey) {
  return ml_dsa87.verify(publicKey, data, signature);
}

function hexToBytes(hex) {
  const clean = String(hex || "").replace(/\s+/g, "");
  if (!clean.length || clean.length % 2 !== 0) return new Uint8Array(0);
  return Uint8Array.from(clean.match(/.{1,2}/g).map((h) => parseInt(h, 16)));
}

function createWalletFromPhrase(phrase) {
  const normalized = normalizeSeedPhrase(phrase);
  if (!isValidSeedPhrase(normalized)) throw new Error("Invalid seed phrase");
  const seed = bip39Seed(normalized);
  const full = deriveFullSeed(seed, 0);
  const kp = generateKeyPairFromSeed(full);
  const address = publicKeyToAddress(kp.publicKey);
  return {
    seedPhrase: normalized,
    address,
    publicKeyHex: kp.publicKeyHex,
    privateKey: kp.privateKey,
  };
}

function createNewWallet() {
  const mnemonic = createMnemonic();
  return { wallet: createWalletFromPhrase(mnemonic), mnemonic };
}

module.exports = {
  createMnemonic,
  createWalletFromPhrase,
  createNewWallet,
  sign,
  verify,
  bytesToHex,
  hexToBytes,
  publicKeyToAddress,
  isValidSeedPhrase,
};
