/**
 * POST /api/agent/register
 *
 * Prepare a registration transaction for an AI agent on the ERC8004IdentityRegistry.
 * Returns unsigned transaction data for the client to sign with their wallet.
 *
 * SECURITY: This route NEVER accepts or handles private keys.
 * All signing is done client-side via the user's wallet (MetaMask, etc.).
 *
 * Body:
 *   - name: string (3-32 chars, lowercase alphanumeric + hyphens)
 *   - walletAddress: string (0x...)
 *   - description?: string (agent description)
 *   - specializations?: string[] (e.g. ["research", "security"])
 *   - capabilities?: string[] (e.g. ["NLP", "Code Generation"])
 *   - identityType?: "human" | "companion" | "agent" (default: "agent")
 *   - chain?: "base" | "avalanche" | "arbitrum" | "polygon" (default: "base")
 *
 * Returns:
 *   - txData: { to, data, value, chainId, gasEstimate } — unsigned transaction
 *   - name: string — formatted VNS name
 *   - message: string — human-readable description
 *
 * Uses verified selector: registerAgent(string,string,bytes32) → 0x2b3ce0bf
 */

import { NextRequest, NextResponse } from 'next/server';
import { resolveChain, SUPPORTED_CHAINS } from '../../_lib/resolve-chain';
import {
  IDENTITY_REGISTRY,
  CHAIN_IDS,
  RPC_URLS,
  EXPLORER_URLS,
  type SupportedChain,
} from '../../../lib/contracts';
import { checkRateLimit, RATE_LIMIT_WRITE } from '../../../lib/rate-limit';

/* ── CORS helpers ── */
const CORS_HEADERS = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'POST, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type',
};

export async function OPTIONS() {
  return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
}

/* ── ABI helpers ── */
function encodeUint256(n: number | bigint): string {
  return BigInt(n).toString(16).padStart(64, '0');
}
function encodeString(s: string): string {
  const utf8 = new TextEncoder().encode(s);
  const length = encodeUint256(utf8.length);
  const paddedLength = Math.ceil(utf8.length / 32) * 32;
  const padded = new Uint8Array(paddedLength);
  padded.set(utf8);
  let hex = '';
  for (const byte of padded) hex += byte.toString(16).padStart(2, '0');
  return length + hex;
}

async function rpcCall(rpcUrl: string, method: string, params: unknown[]) {
  const res = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params }),
    signal: AbortSignal.timeout(12000),
  });
  return res.json();
}

/* ── Address validation ── */
function isValidAddress(addr: string): boolean {
  return /^0x[a-fA-F0-9]{40}$/.test(addr);
}

export async function POST(request: NextRequest) {
  // VF-02: Rate limiting — 20 POST requests per minute per IP
  const rateLimitResponse = checkRateLimit(request, RATE_LIMIT_WRITE);
  if (rateLimitResponse) return rateLimitResponse;

  try {
    const body = await request.json();
    const {
      name: rawName,
      walletAddress,
      description = '',
      specializations = [],
      capabilities = [],
      identityType = 'agent',
      chain: rawChain = 'base',
    } = body;
    const chain = resolveChain(rawChain) || '';

    // SECURITY: Reject requests that include private keys
    if (body.privateKey || body.private_key || body.secret) {
      return NextResponse.json(
        {
          error: 'SECURITY: Private keys must never be sent to a server. Sign transactions client-side using your wallet (MetaMask, WalletConnect, etc.).',
          hint: 'Use the returned txData object with your wallet provider to sign and broadcast.',
        },
        { status: 400, headers: CORS_HEADERS },
      );
    }

    // Validate required fields
    if (!rawName || !walletAddress) {
      return NextResponse.json(
        { error: 'Missing required fields: name, walletAddress' },
        { status: 400, headers: CORS_HEADERS },
      );
    }

    // Validate address format
    if (!isValidAddress(walletAddress)) {
      return NextResponse.json(
        { error: 'Invalid walletAddress format. Must be 0x followed by 40 hex characters.' },
        { status: 400, headers: CORS_HEADERS },
      );
    }

    const name = rawName.toLowerCase().replace(/\.vns$/, '').trim();
    if (name.length < 3 || name.length > 32) {
      return NextResponse.json(
        { error: 'Name must be 3-32 characters' },
        { status: 400, headers: CORS_HEADERS },
      );
    }
    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, headers: CORS_HEADERS },
      );
    }

    if (!SUPPORTED_CHAINS.includes(chain)) {
      return NextResponse.json(
        { error: `Invalid chain. Use: ${SUPPORTED_CHAINS.join(', ')} (or chain IDs: 8453, 43114, 42161, 137)` },
        { status: 400, headers: CORS_HEADERS },
      );
    }

    const rpc = RPC_URLS[chain as SupportedChain];
    const registry = IDENTITY_REGISTRY[chain as SupportedChain];
    const chainId = CHAIN_IDS[chain as SupportedChain];

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

    // Build identityHash
    const identityHashHex = Array.from(new TextEncoder().encode(name))
      .map((b: number) => b.toString(16).padStart(2, '0'))
      .join('')
      .padEnd(64, '0')
      .slice(0, 64);

    // Encode calldata: registerAgent(string, string, bytes32) → 0x2b3ce0bf
    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)
      + identityHashHex
      + nameEncoded
      + descEncoded;

    // Estimate gas
    let gasEstimate = '300000';
    try {
      const gasEstResult = await rpcCall(rpc, 'eth_estimateGas', [
        { from: walletAddress, to: registry, data: calldata },
      ]);
      if (gasEstResult.result) {
        const est = BigInt(gasEstResult.result) * 12n / 10n; // 20% buffer
        gasEstimate = est.toString();
      }
    } catch {
      // Use default 300k
    }

    return NextResponse.json({
      success: true,
      txData: {
        to: registry,
        data: calldata,
        value: '0',
        chainId,
        gasEstimate,
      },
      name: `${name}.vns`,
      chain,
      message: `Sign this transaction with your wallet to register "${name}.vns" on ${chain}`,
      docs: 'https://theloopbreaker.com/developers',
    }, { headers: CORS_HEADERS });
  } catch (e) {
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500, headers: CORS_HEADERS },
    );
  }
}
