/**
 * POST /api/x402/actions/register-agent
 *
 * x402 payment-gated tx-prepare for ERC-8004 agent registration — $0.50 USDC.
 *
 * Returns an unsigned transaction the caller signs in their own wallet.
 * NO private keys are ever accepted or held server-side. The contract uses
 * msg.sender, so the caller's wallet IS the registered agent — that's the
 * only correct, honest pattern. We do all the heavy ABI encoding for you.
 *
 * Body (JSON):
 *   - name: string (3-32 chars, lowercase alphanumeric + hyphens)
 *   - walletAddress: string (0x...) — the agent address that will register
 *   - description?: string
 *   - specializations?: string[]
 *   - capabilities?: string[]
 *   - identityType?: "human" | "companion" | "agent" (default: "agent")
 *   - 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, IDENTITY_REGISTRY, SUPPORTED_CHAINS,
  isValidAddress, isValidChain, encodeUint256, encodeString, encodeBytes32FromString,
  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 {
    name: rawName,
    walletAddress,
    description = '',
    specializations = [],
    capabilities = [],
    identityType = 'agent',
    chain = 'base',
  } = body;

  if (!rawName || !walletAddress) {
    return NextResponse.json({ error: 'Missing required fields: name, walletAddress' }, { status: 400 });
  }
  if (!isValidAddress(walletAddress)) {
    return NextResponse.json({ error: 'Invalid walletAddress' }, { status: 400 });
  }
  if (!isValidChain(chain)) {
    return NextResponse.json({ error: `Invalid chain. Use: ${SUPPORTED_CHAINS.join(', ')}` }, { status: 400 });
  }

  const name = String(rawName).toLowerCase().replace(/\.vns$/, '').trim();
  if (name.length < 3 || name.length > 32) {
    return NextResponse.json({ error: 'name must be 3-32 chars' }, { status: 400 });
  }
  if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(name) && !/^[a-z0-9]{1,2}$/.test(name)) {
    return NextResponse.json({ error: 'Invalid name format. Use lowercase alphanumeric + hyphens.' }, { status: 400 });
  }

  // Build agentURI metadata
  const meta: Record<string, unknown> = { type: identityType, v: 1 };
  if (description) meta.desc = String(description).slice(0, 200);
  if (Array.isArray(specializations) && specializations.length) meta.spec = specializations;
  if (Array.isArray(capabilities) && capabilities.length) meta.caps = capabilities;
  const descJson = JSON.stringify(meta);

  // Calldata for registerAgent(string,string,bytes32) — selector 0x2b3ce0bf
  const identityHash = encodeBytes32FromString(name);
  const nameEncoded = encodeString(name);
  const descEncoded = encodeString(descJson);
  const offset1 = 0x60;
  const string1Size = nameEncoded.length / 2;
  const offset2 = offset1 + string1Size;
  const calldata = '0x2b3ce0bf'
    + encodeUint256(offset1)
    + encodeUint256(offset2)
    + identityHash
    + nameEncoded
    + descEncoded;

  const registry = IDENTITY_REGISTRY[chain];
  const rpc = RPC_URLS[chain];
  const chainId = CHAIN_IDS[chain];
  const gasEstimate = await estimateGas(rpc, walletAddress, registry, calldata);

  return NextResponse.json({
    success: true,
    txData: {
      to: registry,
      data: calldata,
      value: '0',
      chainId,
      gasEstimate,
    },
    name: `${name}.vns`,
    chain,
    explorer: `${EXPLORERS[chain]}/address/${registry}`,
    message: `Sign this transaction in your wallet to register "${name}.vns" on ${chain}. The wallet that signs becomes the agent (msg.sender).`,
    securityNote: 'Vaultfire NEVER accepts private keys. Sign locally in your Base App / MetaMask / WalletConnect.',
    _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/register-agent'),
  PAY_TO,
  {
    price: '$0.50',
    network: 'base',
    config: {
      description: 'Register an AI agent on the ERC-8004 Identity Registry. Pay $0.50 in USDC and receive a fully-encoded unsigned transaction (calldata + gas estimate + chain ID) — sign locally in your wallet to become the registered agent. No private keys ever touch our servers.',
      mimeType: 'application/json',
      outputSchema: {
        input: {
          type: 'http',
          method: 'POST',
          discoverable: true,
          bodySchema: {
            type: 'object',
            required: ['name', 'walletAddress'],
            properties: {
              name: { type: 'string', description: 'Agent display name' },
              walletAddress: { type: 'string', description: 'Agent wallet that will sign and be registered (msg.sender)' },
              description: { type: 'string' },
              specializations: { type: 'array', items: { type: 'string' } },
              capabilities: { type: 'array', items: { type: 'string' } },
              identityType: { type: 'string', enum: ['human', 'companion', 'agent'] },
              chain: { type: 'string', enum: ['base', 'avalanche', 'arbitrum', 'polygon'] },
            },
          },
        },
        output: {
          type: 'object',
          properties: {
            success: { type: 'boolean' },
            txData: { type: 'object' },
            name: { type: 'string' },
            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',
    },
  });
}
