/**
 * Solana x402 Payment Verification
 *
 * Verifies an SPL USDC transfer to PAY_TO_SOL on Solana mainnet by transaction
 * signature. The client signs and submits the Solana transaction in their own
 * wallet (Phantom, Backpack, Solflare, Base App), then includes the tx
 * signature in the Payment-Signature header. We confirm the transaction
 * on-chain via public RPC, validate the recipient + amount + token mint, and
 * grant access.
 *
 * No private keys touch the server. No facilitator dependency. No SOL gas
 * cost on our side — payer pays their own gas.
 */

// USDC SPL token mint on Solana mainnet (Circle, official):
// https://www.circle.com/multi-chain-usdc/solana
const USDC_MINT_SOLANA = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';

// SPL Token Program
const TOKEN_PROGRAM_ID = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';

const SOLANA_RPC = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com';

interface SolanaVerifyResult {
  valid: boolean;
  signer?: string;
  amountAtomic?: string;
  amountHuman?: string;
  signature?: string;
  error?: string;
}

const USDC_DECIMALS = 6n;
const USDC_ATOMIC_UNITS = 10n ** USDC_DECIMALS;

function formatUsdcAtomic(amountAtomic: bigint): string {
  const whole = amountAtomic / USDC_ATOMIC_UNITS;
  const fractional = (amountAtomic % USDC_ATOMIC_UNITS)
    .toString()
    .padStart(6, '0');
  return `${whole}.${fractional}`;
}

/**
 * Verify a Solana USDC payment.
 *
 * @param signature - Solana transaction signature (base58, 64-byte sig)
 * @param expectedRecipient - Solana pubkey that should have received USDC
 * @param minAmountAtomic - Minimum USDC amount in atomic units (6 decimals)
 *                         e.g. '10000' = $0.01 USDC
 */
export async function verifySolanaUSDCPayment(
  signature: string,
  expectedRecipient: string,
  minAmountAtomic: string
): Promise<SolanaVerifyResult> {
  if (!signature || typeof signature !== 'string') {
    return { valid: false, error: 'Missing Solana transaction signature' };
  }
  if (!expectedRecipient || typeof expectedRecipient !== 'string') {
    return { valid: false, error: 'Missing expected recipient pubkey' };
  }
  if (typeof minAmountAtomic !== 'string' || !/^[1-9]\d*$/.test(minAmountAtomic)) {
    return { valid: false, error: 'Minimum USDC amount must be a positive atomic-unit integer' };
  }
  const minimumAmountAtomic = BigInt(minAmountAtomic);

  // Basic shape check — Solana sigs are base58, 87-88 chars typical
  if (signature.length < 80 || signature.length > 100) {
    return { valid: false, error: 'Invalid Solana signature shape' };
  }

  try {
    // Fetch the transaction with parsed jsonParsed encoding for token balance deltas
    const rpcRes = await fetch(SOLANA_RPC, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        id: 1,
        method: 'getTransaction',
        params: [
          signature,
          {
            encoding: 'jsonParsed',
            maxSupportedTransactionVersion: 0,
            commitment: 'confirmed',
          },
        ],
      }),
    });

    if (!rpcRes.ok) {
      return { valid: false, error: `Solana RPC error: ${rpcRes.status}` };
    }

    const data = await rpcRes.json();
    if (data.error) {
      return { valid: false, error: `Solana RPC: ${data.error.message || JSON.stringify(data.error)}` };
    }

    const tx = data.result;
    if (!tx) {
      return { valid: false, error: 'Transaction not found on Solana mainnet (not confirmed yet?)' };
    }

    if (tx.meta?.err) {
      return { valid: false, error: `Transaction failed on-chain: ${JSON.stringify(tx.meta.err)}` };
    }

    // Walk pre/post token balances to find the USDC transfer to expectedRecipient.
    // This is the most robust method — it doesn't depend on instruction shape
    // (Token, Token-2022, transferChecked, transfer, all show up here).
    const preBalances: any[] = tx.meta?.preTokenBalances || [];
    const postBalances: any[] = tx.meta?.postTokenBalances || [];

    // Find any post-balance entry where:
    //   - mint === USDC_MINT_SOLANA
    //   - owner === expectedRecipient
    // Then compute the delta vs the matching pre-balance (or 0 if account is new).
    let largestRecipientDelta = 0n;
    let firstSigner: string | undefined;

    for (const post of postBalances) {
      if (post.mint !== USDC_MINT_SOLANA) continue;
      if (post.owner !== expectedRecipient) continue;

      const postAmt = BigInt(post.uiTokenAmount?.amount || '0');
      const matchingPre = preBalances.find(
        (p) => p.accountIndex === post.accountIndex
      );
      const preAmt = matchingPre ? BigInt(matchingPre.uiTokenAmount?.amount || '0') : 0n;
      const delta = postAmt - preAmt;
      if (delta > largestRecipientDelta) {
        largestRecipientDelta = delta;
      }
    }

    if (largestRecipientDelta <= 0n) {
      return {
        valid: false,
        error: `No USDC transfer to ${expectedRecipient} found in transaction`,
      };
    }

    if (largestRecipientDelta < minimumAmountAtomic) {
      return {
        valid: false,
        error: `Insufficient USDC payment: ${largestRecipientDelta} < ${minAmountAtomic}`,
      };
    }

    // Identify signer — first signature is the fee payer / primary signer
    const accountKeys = tx.transaction?.message?.accountKeys || [];
    if (accountKeys.length > 0) {
      const first = accountKeys[0];
      firstSigner = typeof first === 'string' ? first : first.pubkey;
    }

    const humanAmount = formatUsdcAtomic(largestRecipientDelta);

    return {
      valid: true,
      signer: firstSigner,
      amountAtomic: largestRecipientDelta.toString(),
      amountHuman: `$${humanAmount} USDC`,
      signature,
    };
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    return { valid: false, error: `Solana verify error: ${msg}` };
  }
}

export const SOLANA_USDC_MINT = USDC_MINT_SOLANA;
export const SOLANA_TOKEN_PROGRAM = TOKEN_PROGRAM_ID;
