'use client';

/**
 * Per-endpoint x402 signing page.
 *
 * For each priced endpoint:
 *   1. Fetch 402 challenge → extract paymentRequirements (payTo, asset, amount, extra)
 *   2. Build EIP-3009 TransferWithAuthorization typed data with the EXACT domain
 *      Coinbase's USDC contract on Base verifies (name="USD Coin", version="2", chainId=8453)
 *   3. Ask wallet to sign via eth_signTypedData_v4 — Base App / Coinbase Wallet
 *      handle this natively
 *   4. POST the signature + authorization to /api/x402/submit-signed which assembles
 *      the X-PAYMENT header and submits to the priced endpoint
 *   5. Show settlement tx hash + response
 *
 * Each endpoint = one wallet popup. $0.01–$0.05 per endpoint, totaling ~$0.21
 * for all 12 priced endpoints (self-pay).
 */

import React, { useState, useCallback } from 'react';
import { useWalletAuth } from '../../lib/WalletAuthContext';

const BASE_CHAIN_ID = 8453;
const BASE_CHAIN_HEX = '0x2105';

type EndpointDef = {
  path: string;
  method: 'GET' | 'POST';
  body?: any;
  query?: string;
  label: string;
  priceCents: string; // for display
};

const ENDPOINTS: EndpointDef[] = [
  { path: '/api/x402/trust/agent-status', method: 'GET', query: '?address=0xfA15Ee28939B222B0448261A22156070f0A7813C', label: 'agent-status — deployer profile', priceCents: '$0.01' },
  { path: '/api/x402/trust/protocol-stats', method: 'GET', label: 'protocol-stats — 22 identities', priceCents: '$0.01' },
  { path: '/api/x402/trust/contracts', method: 'GET', label: 'contracts — 134-contract directory', priceCents: '$0.05' },
  { path: '/api/x402/trust/bonds', method: 'GET', query: '?address=0xfA15Ee28939B222B0448261A22156070f0A7813C', label: 'bonds — deployer bond list', priceCents: '$0.01' },
  { path: '/api/x402/trust/insurance', method: 'GET', label: 'insurance — pool stats', priceCents: '$0.01' },
  { path: '/api/x402/trust/disputes', method: 'GET', label: 'disputes — dispute stats', priceCents: '$0.01' },
  { path: '/api/x402/trust/performance', method: 'GET', query: '?address=0xfA15Ee28939B222B0448261A22156070f0A7813C', label: 'performance — oracle stats', priceCents: '$0.01' },
  { path: '/api/x402/trust/vouching', method: 'GET', query: '?address=0xfA15Ee28939B222B0448261A22156070f0A7813C', label: 'vouching — reputation profile', priceCents: '$0.01' },
  { path: '/api/x402/trust/credentials', method: 'GET', query: '?address=0xfA15Ee28939B222B0448261A22156070f0A7813C', label: 'credentials — capabilities', priceCents: '$0.01' },
  { path: '/api/x402/trust/bridge', method: 'GET', label: 'bridge — cross-chain state', priceCents: '$0.02' },
  { path: '/api/x402/trust/analytics', method: 'GET', query: '?address=0xfA15Ee28939B222B0448261A22156070f0A7813C', label: 'analytics — composite profile', priceCents: '$0.05' },
  { path: '/api/x402/contract-call', method: 'POST', body: { chain: 'base', contract: 'ERC8004IdentityRegistry', function: 'getTotalAgents', args: [] }, label: 'contract-call — getTotalAgents()', priceCents: '$0.01' },
];

type EndpointState = {
  status: 'idle' | 'fetching-challenge' | 'awaiting-signature' | 'submitting' | 'done' | 'error';
  msg?: string;
  txHash?: string;
  responsePreview?: string;
};

function rand32HexNonce(): string {
  const bytes = new Uint8Array(32);
  crypto.getRandomValues(bytes);
  return '0x' + Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('');
}

export default function X402PayPage() {
  const { address, chainId, connect, isUnlocked } = useWalletAuth();
  const [states, setStates] = useState<Record<string, EndpointState>>(
    Object.fromEntries(ENDPOINTS.map((e) => [e.path, { status: 'idle' }])),
  );

  const updateState = useCallback((path: string, patch: Partial<EndpointState>) => {
    setStates((s) => ({ ...s, [path]: { ...s[path], ...patch } }));
  }, []);

  async function ensureBase() {
    if (chainId === BASE_CHAIN_ID) return;
    const eth = (window as any).ethereum;
    if (!eth) throw new Error('No wallet provider detected');
    await eth.request({
      method: 'wallet_switchEthereumChain',
      params: [{ chainId: BASE_CHAIN_HEX }],
    });
  }

  async function signAndSubmitOne(ep: EndpointDef) {
    const eth = (window as any).ethereum;
    if (!eth) {
      updateState(ep.path, { status: 'error', msg: 'No wallet provider detected' });
      return;
    }
    if (!address) {
      updateState(ep.path, { status: 'error', msg: 'Connect wallet first' });
      return;
    }

    updateState(ep.path, { status: 'fetching-challenge', msg: 'Fetching 402 challenge…' });

    // Step 1: get 402 challenge
    let challenge: any;
    try {
      await ensureBase();
      const resp = await fetch(window.location.origin + ep.path + (ep.query ?? ''), {
        method: ep.method,
        headers: ep.method === 'POST' ? { 'Content-Type': 'application/json' } : {},
        body: ep.method === 'POST' ? JSON.stringify(ep.body ?? {}) : undefined,
      });
      if (resp.status !== 402) {
        const t = await resp.text();
        throw new Error(`expected 402, got ${resp.status}: ${t.slice(0, 120)}`);
      }
      challenge = await resp.json();
    } catch (e: any) {
      updateState(ep.path, { status: 'error', msg: 'Challenge failed: ' + (e?.message ?? String(e)) });
      return;
    }

    const accept = challenge.accepts?.[0];
    if (!accept) {
      updateState(ep.path, { status: 'error', msg: '402 had no accepts' });
      return;
    }

    // Step 2: build EIP-712 typed data — exact USDC TransferWithAuthorization
    const now = Math.floor(Date.now() / 1000);
    const validAfter = (now - 600).toString();
    const validBefore = (now + (accept.maxTimeoutSeconds ?? 300)).toString();
    const nonce = rand32HexNonce();

    const typedData = {
      types: {
        EIP712Domain: [
          { name: 'name', type: 'string' },
          { name: 'version', type: 'string' },
          { name: 'chainId', type: 'uint256' },
          { name: 'verifyingContract', type: 'address' },
        ],
        TransferWithAuthorization: [
          { name: 'from', type: 'address' },
          { name: 'to', type: 'address' },
          { name: 'value', type: 'uint256' },
          { name: 'validAfter', type: 'uint256' },
          { name: 'validBefore', type: 'uint256' },
          { name: 'nonce', type: 'bytes32' },
        ],
      },
      primaryType: 'TransferWithAuthorization',
      domain: {
        name: accept.extra?.name ?? 'USD Coin',
        version: accept.extra?.version ?? '2',
        chainId: BASE_CHAIN_ID,
        verifyingContract: accept.asset,
      },
      message: {
        from: address,
        to: accept.payTo,
        value: accept.maxAmountRequired,
        validAfter,
        validBefore,
        nonce,
      },
    };

    updateState(ep.path, { status: 'awaiting-signature', msg: 'Approve in wallet…' });

    // Step 3: ask wallet to sign
    let signature: string;
    try {
      signature = await eth.request({
        method: 'eth_signTypedData_v4',
        params: [address, JSON.stringify(typedData)],
      });
    } catch (e: any) {
      updateState(ep.path, { status: 'error', msg: 'Signature rejected/failed: ' + (e?.message ?? String(e)) });
      return;
    }

    updateState(ep.path, { status: 'submitting', msg: 'Submitting payment to facilitator…' });

    // Step 4: POST to submit-signed which assembles X-PAYMENT and forwards
    let result: any;
    try {
      const resp = await fetch('/api/x402/submit-signed', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          targetPath: ep.path,
          method: ep.method,
          query: ep.query,
          body: ep.body,
          authorization: typedData.message,
          signature,
          network: accept.network,
          scheme: accept.scheme,
          x402Version: challenge.x402Version ?? 1,
        }),
      });
      result = await resp.json();
    } catch (e: any) {
      updateState(ep.path, { status: 'error', msg: 'Submit failed: ' + (e?.message ?? String(e)) });
      return;
    }

    if (!result.ok) {
      updateState(ep.path, {
        status: 'error',
        msg: `submit returned ${result.status}: ${JSON.stringify(result.response).slice(0, 200)}`,
      });
      return;
    }

    updateState(ep.path, {
      status: 'done',
      msg: 'Settled on-chain',
      txHash: result.settlement?.transaction,
      responsePreview: JSON.stringify(result.response).slice(0, 180),
    });
  }

  async function signAll() {
    for (const ep of ENDPOINTS) {
      await signAndSubmitOne(ep);
      // small pause so the wallet UI can fully close before next popup
      await new Promise((r) => setTimeout(r, 400));
    }
  }

  return (
    <main style={{
      maxWidth: 720, margin: '0 auto', padding: '24px 16px 80px',
      fontFamily: 'system-ui, -apple-system, sans-serif', color: '#fff',
      background: '#0c0c10', minHeight: '100vh',
    }}>
      <h1 style={{ fontSize: 22, marginBottom: 4 }}>x402 live settlement test</h1>
      <p style={{ color: '#9ca3af', fontSize: 14, marginBottom: 16 }}>
        Sign each endpoint to settle one real USDC payment on Base. Self-pay
        (you pay yourself), about $0.21 total in protocol fees.
      </p>

      <div style={{
        background: '#15151c', border: '1px solid #26262e', borderRadius: 8,
        padding: 12, marginBottom: 16,
      }}>
        <div style={{ fontSize: 13 }}>
          <strong>Wallet:</strong>{' '}
          {address ? (
            <span style={{ color: '#86efac' }}>{address}</span>
          ) : (
            <button
              onClick={connect}
              style={{ background: '#2563eb', color: '#fff', border: 'none', padding: '6px 12px', borderRadius: 6, cursor: 'pointer' }}
            >
              Connect wallet
            </button>
          )}
        </div>
        <div style={{ fontSize: 13, marginTop: 4 }}>
          <strong>Chain:</strong>{' '}
          {chainId === BASE_CHAIN_ID
            ? <span style={{ color: '#86efac' }}>Base mainnet</span>
            : <span style={{ color: '#fca5a5' }}>not on Base (will switch when you sign)</span>}
        </div>
      </div>

      {address && (
        <button
          onClick={signAll}
          disabled={!isUnlocked}
          style={{
            background: '#16a34a', color: '#fff', border: 'none',
            padding: '12px 16px', borderRadius: 8, cursor: 'pointer',
            fontWeight: 600, marginBottom: 16, width: '100%',
          }}
        >
          Sign + settle all 12 (one popup at a time)
        </button>
      )}

      {ENDPOINTS.map((ep) => {
        const s = states[ep.path];
        const color =
          s.status === 'done' ? '#86efac' :
          s.status === 'error' ? '#fca5a5' :
          s.status === 'idle' ? '#9ca3af' : '#fcd34d';
        return (
          <div key={ep.path} style={{
            background: '#15151c', border: '1px solid #26262e', borderRadius: 8,
            padding: 12, marginBottom: 8, fontSize: 13,
          }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8 }}>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontWeight: 600 }}>{ep.label}</div>
                <div style={{ color: '#6b7280', fontSize: 11, wordBreak: 'break-all' }}>
                  {ep.method} {ep.path} • {ep.priceCents}
                </div>
              </div>
              <button
                onClick={() => signAndSubmitOne(ep)}
                disabled={!address || s.status === 'awaiting-signature' || s.status === 'submitting' || s.status === 'fetching-challenge'}
                style={{
                  background: '#1f2937', color: '#fff', border: '1px solid #374151',
                  padding: '6px 10px', borderRadius: 6, cursor: 'pointer',
                  fontSize: 12, whiteSpace: 'nowrap',
                }}
              >
                {s.status === 'done' ? 'Done' : 'Sign'}
              </button>
            </div>
            {s.msg && (
              <div style={{ marginTop: 6, color, fontSize: 12 }}>
                {s.msg}
              </div>
            )}
            {s.txHash && (
              <div style={{ marginTop: 4, fontSize: 11 }}>
                <a
                  href={`https://basescan.org/tx/${s.txHash}`}
                  target="_blank" rel="noreferrer"
                  style={{ color: '#60a5fa', wordBreak: 'break-all' }}
                >
                  {s.txHash}
                </a>
              </div>
            )}
            {s.responsePreview && (
              <div style={{ marginTop: 4, fontSize: 11, color: '#9ca3af', wordBreak: 'break-all' }}>
                {s.responsePreview}
              </div>
            )}
          </div>
        );
      })}
    </main>
  );
}
