/**
 * Passkey-backed x402 Signer
 *
 * Client-side module that uses the EncryptID passkey (WebAuthn PRF) to
 * derive an EOA and sign x402 micropayments. Replaces the EVM_PRIVATE_KEY
 * env var approach with hardware-backed passkey signing.
 *
 * Flow:
 *   1. Authenticate with passkey (gets PRF output)
 *   2. Derive EOA via deriveEOAFromPRF()
 *   3. Create x402 client with EOA as signer
 *   4. Return wrapped fetch that auto-handles 402 responses
 *   5. Zero the private key bytes after signing
 */

import { deriveEOAFromPRF, zeroPrivateKey } from '../../src/encryptid/eoa-derivation';
import type { DerivedKeys } from '../../src/encryptid/key-derivation';

/**
 * Options for creating a passkey-backed x402 fetch wrapper.
 */
export interface PasskeySignerOptions {
  /** Network identifier (default: 'eip155:84532' for Base Sepolia) */
  network?: string;
  /** PRF output from passkey authentication */
  prfOutput: Uint8Array;
}

/**
 * Result from creating a passkey signer, including cleanup.
 */
export interface PasskeySignerResult {
  /** The fetch function with x402 payment handling */
  paidFetch: typeof fetch;
  /** The derived EOA address */
  eoaAddress: string;
  /** Call this to zero out the private key from memory */
  cleanup: () => void;
}

/**
 * Create a passkey-backed x402 payment signer.
 *
 * Derives an EOA from the passkey PRF output and creates a fetch wrapper
 * that automatically handles 402 Payment Required responses by signing
 * USDC transfers on the specified network.
 *
 * @example
 * ```ts
 * const { paidFetch, eoaAddress, cleanup } = await createPasskeySigner({
 *   prfOutput: prfOutputBytes,
 *   network: 'eip155:84532',
 * });
 *
 * try {
 *   const res = await paidFetch('https://example.com/paid-endpoint', {
 *     method: 'POST',
 *     body: JSON.stringify({ data: 'test' }),
 *   });
 *   console.log('Payment + response:', await res.json());
 * } finally {
 *   cleanup(); // Zero private key
 * }
 * ```
 */
export async function createPasskeySigner(
  options: PasskeySignerOptions,
): Promise<PasskeySignerResult> {
  const network = options.network || 'eip155:84532';

  // Derive EOA from PRF output
  const eoa = deriveEOAFromPRF(options.prfOutput);

  // Dynamic imports for x402 client libraries (only loaded when needed)
  const [{ x402Client, wrapFetchWithPayment }, { ExactEvmScheme }, { privateKeyToAccount }] =
    await Promise.all([
      import('@x402/fetch'),
      import('@x402/evm/exact/client'),
      import('viem/accounts'),
    ]);

  // Convert raw private key bytes to viem account
  const hexKey = ('0x' + Array.from(eoa.privateKey).map(b => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`;
  const account = privateKeyToAccount(hexKey);

  // Set up x402 client with the derived EOA
  // Type cast needed: viem's LocalAccount doesn't include readContract,
  // but ExactEvmScheme only uses signing methods at runtime
  const client = new x402Client();
  client.register(network as `${string}:${string}`, new ExactEvmScheme(account as any));

  const paidFetch = wrapFetchWithPayment(fetch as any, client) as unknown as typeof fetch;

  return {
    paidFetch,
    eoaAddress: eoa.address,
    cleanup: () => {
      zeroPrivateKey(eoa.privateKey);
    },
  };
}

/**
 * Create a passkey signer directly from EncryptID DerivedKeys.
 *
 * Convenience wrapper when keys are already available from the key manager.
 */
export async function createPasskeySignerFromKeys(
  keys: DerivedKeys,
  network?: string,
): Promise<PasskeySignerResult | null> {
  if (!keys.eoaPrivateKey || !keys.eoaAddress) {
    return null;
  }

  const net = network || 'eip155:84532';

  const [{ x402Client, wrapFetchWithPayment }, { ExactEvmScheme }, { privateKeyToAccount }] =
    await Promise.all([
      import('@x402/fetch'),
      import('@x402/evm/exact/client'),
      import('viem/accounts'),
    ]);

  const hexKey = ('0x' + Array.from(keys.eoaPrivateKey).map(b => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`;
  const account = privateKeyToAccount(hexKey);

  const client = new x402Client();
  client.register(net as `${string}:${string}`, new ExactEvmScheme(account as any));

  const paidFetch = wrapFetchWithPayment(fetch as any, client) as unknown as typeof fetch;

  return {
    paidFetch,
    eoaAddress: keys.eoaAddress,
    cleanup: () => {
      if (keys.eoaPrivateKey) {
        zeroPrivateKey(keys.eoaPrivateKey);
      }
    },
  };
}
