/**
 * POST /api/x402/actions/batch-onboard — $0.50 USDC
 * Calls VaultfireBatchOnboarder.onboardAndBond(string,string,bytes32,address,string)
 * Selector 0x5bd38047 (verified vs viem.toFunctionSelector + on-chain dispatcher)
 *
 * EIP-7702 stateless delegate — one signature registers an agent in the
 * ERC-8004 identity registry AND opens a partnership bond. Base-only.
 */
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, BATCH_ONBOARDER,
  isValidAddress, isValidBytes32, encodeUint256, encodeAddress, encodeString, encodeBytes32, estimateGas, rejectsPrivateKeyShape,
} from '../_lib/tx-encode';

const PAY_TO = '0xfA15Ee28939B222B0448261A22156070f0A7813C';

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, name, agentURI, purposeHash, partner, partnershipType = '', chain = 'base' } = body;
  if (!walletAddress || !name || !agentURI || !purposeHash || !partner) {
    return NextResponse.json({ error: 'Missing required fields: walletAddress, name, agentURI, purposeHash, partner' }, { status: 400 });
  }
  if (!isValidAddress(walletAddress)) return NextResponse.json({ error: 'Invalid walletAddress' }, { status: 400 });
  if (!isValidAddress(partner)) return NextResponse.json({ error: 'Invalid partner address' }, { status: 400 });
  if (!isValidBytes32(purposeHash)) return NextResponse.json({ error: 'purposeHash must be 0x + 64 hex chars (bytes32)' }, { status: 400 });
  if (chain !== 'base') return NextResponse.json({ error: 'VaultfireBatchOnboarder is deployed only on Base. Use chain="base".' }, { status: 400 });
  if (typeof name !== 'string' || name.length === 0 || name.length > 128) return NextResponse.json({ error: 'name must be 1-128 chars' }, { status: 400 });
  if (typeof agentURI !== 'string' || agentURI.length === 0 || agentURI.length > 1024) return NextResponse.json({ error: 'agentURI must be 1-1024 chars' }, { status: 400 });
  if (typeof partnershipType !== 'string' || partnershipType.length > 128) return NextResponse.json({ error: 'partnershipType must be ≤128 chars' }, { status: 400 });

  // onboardAndBond(string,string,bytes32,address,string)
  // Static head: 5 slots = 0xa0 bytes
  // offset_name=0xa0 | offset_agentURI=? | purposeHash | partner | offset_partnershipType=?
  // We'll compute lengths after the head.
  const nameEnc = encodeString(name);              // length(32) + padded body
  const agentURIEnc = encodeString(agentURI);
  const partnershipEnc = encodeString(partnershipType);

  const offsetName = 0xa0;
  const offsetAgentURI = offsetName + nameEnc.length / 2;
  const offsetPartnership = offsetAgentURI + agentURIEnc.length / 2;

  const head = encodeUint256(offsetName)
    + encodeUint256(offsetAgentURI)
    + encodeBytes32(purposeHash)
    + encodeAddress(partner)
    + encodeUint256(offsetPartnership);

  const calldata = '0x5bd38047' + head + nameEnc + agentURIEnc + partnershipEnc;
  const contract = BATCH_ONBOARDER[chain];
  const gasEstimate = await estimateGas(RPC_URLS[chain], walletAddress, contract, calldata);

  return NextResponse.json({
    success: true,
    txData: { to: contract, data: calldata, value: '0', chainId: CHAIN_IDS[chain], gasEstimate },
    chain,
    explorer: `${EXPLORERS[chain]}/address/${contract}`,
    message: `Sign once on Base to register "${name}" in ERC-8004 AND open a partnership bond with ${partner}. EIP-7702 stateless delegate handles both atomically.`,
    securityNote: 'Vaultfire NEVER accepts private keys. Atomic — either both ops succeed or the tx reverts.',
    _x402: { paid: true, price: '$0.50 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.50', '/actions/batch-onboard'), PAY_TO, {
  price: '$0.50', network: 'base',
  config: {
    description: 'Tx-prepare for VaultfireBatchOnboarder.onboardAndBond() — EIP-7702 one-sig register + bond on Base. Returns unsigned transaction; caller signs in wallet.',
    mimeType: 'application/json',
    outputSchema: {
      input: { type: 'http', method: 'POST', discoverable: true,
        bodySchema: {
          type: 'object', required: ['walletAddress', 'name', 'agentURI', 'purposeHash', 'partner'],
          properties: {
            walletAddress: { type: 'string' },
            name: { type: 'string', description: 'Agent display name (1-128 chars)' },
            agentURI: { type: 'string', description: 'Agent metadata URI (1-1024 chars)' },
            purposeHash: { type: 'string', description: 'bytes32 ERC-8004 purpose hash' },
            partner: { type: 'string', description: 'Partner address for the bond' },
            partnershipType: { type: 'string', description: 'Optional partnership type label' },
            chain: { type: 'string', enum: ['base'], description: 'Only "base" is supported' },
          },
        },
      },
      output: { type: 'object', properties: { success: { type: 'boolean' }, txData: { type: 'object' }, chain: { 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' } });
}
