/**
 * POST /api/x402/actions/file-vouch
 *
 * x402 payment-gated tx-prepare for VaultfireReputationStaking.vouch() — $0.25 USDC.
 *
 * Returns an unsigned transaction the caller signs in their own wallet.
 * The vouch() function is payable — caller stakes ETH alongside the vouch.
 * NO private keys are ever accepted server-side.
 *
 * Body (JSON):
 *   - walletAddress: string (the voucher — your wallet)
 *   - targetAgent: string (0x... — the agent you want to vouch for)
 *   - stakeWei: string (wei to stake, default "10000000000000000" = 0.01 ETH)
 *   - chain?: "base" | "avalanche" | "arbitrum" | "polygon" (default: "base")
 *
 * Returns:
 *   txData: { to, data, value, chainId, gasEstimate } — sign in your wallet.
 */

import { NextRequest, NextResponse } from 'next/server';
import { withX402 } from 'x402-next';
import { facilitator } from '@coinbase/x402';
import { withActionLogging } from '../_lib/log-action';
import {
  CHAIN_IDS, RPC_URLS, EXPLORERS, REPUTATION_STAKING, SUPPORTED_CHAINS,
  isValidAddress, isValidChain, encodeAddress,
  estimateGas, rejectsPrivateKeyShape,
} from '../_lib/tx-encode';

const PAY_TO = '0xfA15Ee28939B222B0448261A22156070f0A7813C';
const DEFAULT_STAKE_WEI = '10000000000000000'; // 0.01 ETH

const handler = async (req: NextRequest) => {
  let body: any;
  try { body = await req.json(); } catch { body = {}; }

  const keyErr = rejectsPrivateKeyShape(body);
  if (keyErr) return NextResponse.json({ error: keyErr }, { status: 400 });

  const { walletAddress, targetAgent, stakeWei = DEFAULT_STAKE_WEI, chain = 'base' } = body;

  if (!walletAddress || !targetAgent) {
    return NextResponse.json({ error: 'Missing required fields: walletAddress, targetAgent' }, { status: 400 });
  }
  if (!isValidAddress(walletAddress) || !isValidAddress(targetAgent)) {
    return NextResponse.json({ error: 'Invalid address(es)' }, { status: 400 });
  }
  if (walletAddress.toLowerCase() === targetAgent.toLowerCase()) {
    return NextResponse.json({ error: 'Cannot vouch for yourself' }, { status: 400 });
  }
  if (!isValidChain(chain)) {
    return NextResponse.json({ error: `Invalid chain. Use: ${SUPPORTED_CHAINS.join(', ')}` }, { status: 400 });
  }
  let stakeBigInt: bigint;
  try {
    stakeBigInt = BigInt(stakeWei);
    if (stakeBigInt <= 0n) throw new Error();
  } catch {
    return NextResponse.json({ error: 'Invalid stakeWei (must be positive integer string)' }, { status: 400 });
  }

  // Calldata for vouch(address) — selector 0xdd66e16b
  const calldata = '0xdd66e16b' + encodeAddress(targetAgent);
  const valueHex = '0x' + stakeBigInt.toString(16);

  const staking = REPUTATION_STAKING[chain];
  const rpc = RPC_URLS[chain];
  const chainId = CHAIN_IDS[chain];
  const gasEstimate = await estimateGas(rpc, walletAddress, staking, calldata, valueHex);

  return NextResponse.json({
    success: true,
    txData: {
      to: staking,
      data: calldata,
      value: stakeBigInt.toString(),
      chainId,
      gasEstimate,
    },
    chain,
    voucher: walletAddress,
    targetAgent,
    stakeWei: stakeBigInt.toString(),
    contract: staking,
    explorer: `${EXPLORERS[chain]}/address/${staking}`,
    message: `Sign in your wallet (${walletAddress}) to vouch for ${targetAgent} on ${chain} with ${stakeBigInt.toString()} wei (~${(Number(stakeBigInt) / 1e18).toFixed(4)} native).`,
    securityNote: 'Vaultfire NEVER accepts private keys. Sign locally in your Base App / MetaMask / WalletConnect.',
    _x402: {
      paid: true,
      price: '$0.25 USDC',
      service: 'vaultfire-trust',
      facilitator: 'cdp',
      pattern: 'tx-prepare (caller signs)',
    },
  }, { headers: { 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'no-store' } });
};

export const POST = withX402(
  withActionLogging(handler, '$0.25', '/actions/file-vouch'),
  PAY_TO,
  {
    price: '$0.25',
    network: 'base',
    config: {
      description: 'File a vouch (with stake) for another AI agent via VaultfireReputationStaking. Pay $0.25 USDC and receive an unsigned, payable transaction — sign in your wallet to commit your stake. No private keys handled server-side.',
      mimeType: 'application/json',
      outputSchema: {
        input: {
          type: 'http',
          method: 'POST',
          discoverable: true,
          bodySchema: {
            type: 'object',
            required: ['walletAddress', 'targetAgent'],
            properties: {
              walletAddress: { type: 'string', description: 'Voucher wallet that will sign and stake' },
              targetAgent: { type: 'string', description: 'Agent address being vouched for' },
              stakeWei: { type: 'string', description: 'Wei to stake (default 0.01 ETH = 10000000000000000)' },
              chain: { type: 'string', enum: ['base', 'avalanche', 'arbitrum', 'polygon'] },
            },
          },
        },
        output: {
          type: 'object',
          properties: {
            success: { type: 'boolean' },
            txData: { type: 'object' },
            chain: { type: 'string' },
            explorer: { type: 'string' },
            message: { type: 'string' },
          },
        },
      },
    },
  },
  facilitator,
);

export async function OPTIONS() {
  return new NextResponse(null, {
    status: 204,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type',
    },
  });
}
