/**
 * POST /api/agent/bond
 *
 * Prepare a bond transaction for an AI agent on AIPartnershipBondsV2.
 * 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:
 *   - walletAddress: string (0x... — the wallet paying the bond)
 *   - agentAddress: string (0x... — the agent receiving the bond)
 *   - amountEth: number (bond amount in ETH, min 0.01)
 *   - partnershipType?: string (default: "agent:{address}")
 *   - chain?: "base" | "avalanche" | "arbitrum" | "polygon" (default: "base")
 *
 * Returns:
 *   - txData: { to, data, value, chainId, gasEstimate } — unsigned transaction
 *   - tier: string — bond tier based on amount
 *   - message: string — human-readable description
 *
 * Bond tiers:
 *   Bronze:   0.01+ ETH
 *   Silver:   0.05+ ETH
 *   Gold:     0.1+  ETH
 *   Platinum: 0.5+  ETH
 */

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

function encodeAddress(address: string): string {
  return address.replace('0x', '').toLowerCase().padStart(64, '0');
}
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;
}

function getBondTier(ethAmount: number): string {
  if (ethAmount >= 0.5) return 'platinum';
  if (ethAmount >= 0.1) return 'gold';
  if (ethAmount >= 0.05) return 'silver';
  return 'bronze';
}

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 {
      walletAddress,
      agentAddress,
      amountEth,
      partnershipType,
      chain: rawChain = 'base',
    } = body;
    const chain = resolveChain(rawChain) || '';

    // Validate required fields — privateKey is explicitly NOT accepted
    if (!walletAddress || !agentAddress || !amountEth) {
      return NextResponse.json(
        { error: 'Missing required fields: walletAddress, agentAddress, amountEth' },
        { status: 400 },
      );
    }

    // Reject any request that includes a private key
    if (body.privateKey) {
      return NextResponse.json(
        {
          error: 'SECURITY: This endpoint does not accept private keys. ' +
            'Transaction signing must be done client-side via your wallet.',
        },
        { status: 400 },
      );
    }

    const parsedAmount = typeof amountEth === 'string' ? parseFloat(amountEth) : amountEth;
    if (typeof parsedAmount !== 'number' || isNaN(parsedAmount) || parsedAmount < 0.01) {
      return NextResponse.json({ error: 'Minimum bond is 0.01 ETH (amountEth must be a number >= 0.01)' }, { status: 400 });
    }

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

    const bondContract = PARTNERSHIP_BONDS[chain as SupportedChain];
    const chainId = CHAIN_IDS[chain as SupportedChain];
    const bondWei = BigInt(Math.floor(parsedAmount * 1e18));

    // Encode calldata: createBond(address, string) → 0x7ac5113b
    const addressParam = encodeAddress(agentAddress);
    const stringOffset = encodeUint256(0x40); // 2 slots: address + offset
    const pType = partnershipType || `agent:${agentAddress.slice(0, 10)}`;
    const stringEncoded = encodeString(pType);
    const calldata = '7ac5113b' + addressParam + stringOffset + stringEncoded;

    const tier = getBondTier(parsedAmount);

    // Return unsigned transaction data for client-side signing
    return NextResponse.json({
      success: true,
      txData: {
        to: bondContract,
        data: '0x' + calldata,
        value: '0x' + bondWei.toString(16),
        chainId,
        gasEstimate: '250000',
      },
      tier,
      amountEth: parsedAmount,
      chain,
      explorerBaseUrl: EXPLORER_URLS[chain as SupportedChain],
      message: `Sign this transaction with your wallet to stake a ${tier} bond (${parsedAmount} ETH) for agent ${agentAddress.slice(0, 10)}...`,
    });
  } catch (e) {
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 },
    );
  }
}
