/**
 * Basic x402 Payment Example (TypeScript)
 *
 * Demonstrates how to:
 *   1. Configure the x402 client with a WalletProvider
 *   2. Initiate a direct USDC payment to an address
 *   3. Make a payment-gated HTTP request (x402Fetch)
 *   4. Check USDC balance before paying
 *
 * To run:
 *   VAULTFIRE_AGENT_KEY=<your-private-key> npx ts-node examples/basic-payment.ts
 *
 * Dependencies:
 *   npm install ethers
 */

import {
  configureX402,
  initiatePayment,
  x402Fetch,
  getUsdcBalance,
  formatUsdc,
  parseUsdc,
  WalletProvider,
  X402ClientConfig,
} from '../src/x402-client';

// ---------------------------------------------------------------------------
// 1. Create a WalletProvider from environment variable
//    In production, this could wrap MetaMask, a hardware wallet, or a
//    custodial key stored in a secrets manager.
// ---------------------------------------------------------------------------

function createEnvWalletProvider(): WalletProvider {
  const privateKey = process.env['VAULTFIRE_AGENT_KEY'];
  if (!privateKey) {
    throw new Error('Set VAULTFIRE_AGENT_KEY environment variable to your private key.');
  }

  // Derive address synchronously using ethers
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const { ethers } = require('ethers') as typeof import('ethers');
  const key = privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`;
  const wallet = new ethers.Wallet(key);

  return {
    getAddress: () => wallet.address,
    getPrivateKey: () => key, // SECURITY: never log this value
    isUnlocked: () => true,
  };
}

// ---------------------------------------------------------------------------
// 2. Configure the x402 client
// ---------------------------------------------------------------------------

async function setup() {
  const walletProvider = createEnvWalletProvider();
  configureX402(walletProvider);
  console.log(`[x402] Wallet: ${walletProvider.getAddress()}`);
  return walletProvider;
}

// ---------------------------------------------------------------------------
// 3. Check USDC balance
// ---------------------------------------------------------------------------

async function checkBalance(address: string) {
  const balanceMicro = await getUsdcBalance(address);
  const balanceHuman = formatUsdc(balanceMicro);
  console.log(`[x402] USDC Balance (Base): ${balanceHuman} USDC (${balanceMicro} micro)`);
  return balanceMicro;
}

// ---------------------------------------------------------------------------
// 4. Initiate a direct payment to an address
// ---------------------------------------------------------------------------

async function sendDirectPayment() {
  const RECIPIENT = '0xfA15Ee28939B222B0448261A22156070f0A7813C'; // Vaultfire deployer
  const AMOUNT_USDC = '0.01'; // 0.01 USDC = 10,000 micro-USDC

  console.log(`\n[x402] Initiating payment of ${AMOUNT_USDC} USDC to ${RECIPIENT}...`);

  const { payload, record } = await initiatePayment(
    RECIPIENT,
    AMOUNT_USDC,
    'Test payment from vaultfire-x402 basic example',
  );

  console.log('[x402] Payment signed successfully!');
  console.log(`  Payment ID:  ${record.id}`);
  console.log(`  Amount:      ${record.amountFormatted} USDC`);
  console.log(`  To:          ${record.payTo}`);
  console.log(`  Status:      ${record.status}`);
  console.log(`  Nonce:       ${payload.payload.authorization.nonce}`);
  console.log(`  Valid until: ${new Date(parseInt(payload.payload.authorization.validBefore) * 1000).toISOString()}`);

  // The payload can now be:
  // - Sent to the facilitator: https://x402.org/facilitator/settle
  // - Attached to an XMTP message as a transaction reference
  // - Submitted to your /api/x402/settle endpoint
  return { payload, record };
}

// ---------------------------------------------------------------------------
// 5. Make a payment-gated HTTP request
// ---------------------------------------------------------------------------

async function fetchWithPayment() {
  // Example: request a paid API endpoint
  const PAID_API_URL = 'https://api.example.com/premium-data';

  console.log(`\n[x402] Fetching payment-gated resource: ${PAID_API_URL}`);

  const config: X402ClientConfig = {
    autoPay: true,
    maxAutoPayAmount: '0.10', // auto-pay up to $0.10 USDC
    facilitatorUrl: 'https://x402.org/facilitator',
  };

  const result = await x402Fetch(PAID_API_URL, {}, config);

  if (result.paid) {
    console.log('[x402] Payment made and resource retrieved!');
    console.log(`  Amount: ${result.paymentPayload?.accepted.amount} micro-USDC`);
    console.log(`  Settlement tx: ${result.settlement?.txHash || 'pending'}`);
    const data = await result.response.json();
    console.log('[x402] Response:', JSON.stringify(data, null, 2));
  } else if (result.error) {
    console.log(`[x402] Could not complete payment: ${result.error}`);
  } else {
    console.log('[x402] Resource returned without payment (200 OK)');
  }

  return result;
}

// ---------------------------------------------------------------------------
// 6. Parse and format USDC amounts
// ---------------------------------------------------------------------------

function demonstrateAmountHelpers() {
  console.log('\n[x402] Amount conversion examples:');

  const amounts = ['0.01', '1.00', '1.50', '10.00', '100.000001'];
  for (const human of amounts) {
    const micro = parseUsdc(human);
    const back = formatUsdc(micro);
    console.log(`  ${human} USDC → ${micro} micro → ${back} USDC`);
  }
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

async function main() {
  console.log('=== Vaultfire x402 Payment Protocol — Basic Example ===\n');

  try {
    const wallet = await setup();
    demonstrateAmountHelpers();

    const address = wallet.getAddress();
    if (address) {
      await checkBalance(address);
    }

    // Demonstrate signing a direct payment (does not submit on-chain)
    await sendDirectPayment();

    // Demonstrate payment-gated fetch (will 404 unless the API exists)
    // Uncomment to test against a real x402-enabled endpoint:
    // await fetchWithPayment();
  } catch (err) {
    console.error('[x402] Error:', err instanceof Error ? err.message : err);
    process.exit(1);
  }
}

main();
