/**
 * POST /api/x402/actions/create-session-key — $0.25 USDC
 * Calls VKPSessionKeyManager.createSession(address,uint256,uint256,uint256,address[])
 * Selector 0xeee0cbc8 (verified vs viem.toFunctionSelector + on-chain dispatcher)
 *
 * Creates a Vaultfire Knowledge Protocol session key — a scoped, time-bounded
 * delegation that lets a session signer act on behalf of the owner with a
 * spending cap and per-tx limit, restricted to a specific contract allowlist.
 */
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, VKP_SESSION_KEY_MANAGER,
  isValidAddress, isValidChain, encodeUint256, encodeAddress, 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, sessionSigner, expiry, spendingLimitWei, perTxLimitWei, allowedContracts = [], chain = 'base' } = body;
  if (!walletAddress || !sessionSigner || expiry === undefined || spendingLimitWei === undefined || perTxLimitWei === undefined) {
    return NextResponse.json({ error: 'Missing required fields: walletAddress, sessionSigner, expiry, spendingLimitWei, perTxLimitWei' }, { status: 400 });
  }
  if (!isValidAddress(walletAddress)) return NextResponse.json({ error: 'Invalid walletAddress' }, { status: 400 });
  if (!isValidAddress(sessionSigner)) return NextResponse.json({ error: 'Invalid sessionSigner' }, { status: 400 });
  if (!isValidChain(chain)) return NextResponse.json({ error: 'Invalid chain' }, { status: 400 });
  if (!Array.isArray(allowedContracts)) return NextResponse.json({ error: 'allowedContracts must be an array' }, { status: 400 });
  for (const a of allowedContracts) {
    if (!isValidAddress(a)) return NextResponse.json({ error: `Invalid allowedContracts entry: ${a}` }, { status: 400 });
  }

  // createSession(address,uint256,uint256,uint256,address[]) — selector 0xeee0cbc8
  // Layout: head(160) = sessionSigner | expiry | spendingLimit | perTxLimit | offset_to_array(0xa0)
  // Then array: length + entries
  const head = encodeAddress(sessionSigner)
    + encodeUint256(BigInt(expiry))
    + encodeUint256(BigInt(spendingLimitWei))
    + encodeUint256(BigInt(perTxLimitWei))
    + encodeUint256(0xa0); // offset to dynamic array
  const arrayLen = encodeUint256(allowedContracts.length);
  const arrayBody = allowedContracts.map((a: string) => encodeAddress(a)).join('');
  const calldata = '0xeee0cbc8' + head + arrayLen + arrayBody;

  const contract = VKP_SESSION_KEY_MANAGER[chain];
  if (!contract) return NextResponse.json({ error: `VKPSessionKeyManager not deployed on ${chain}` }, { status: 400 });
  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 to create a Vaultfire session key on ${chain}. Signer ${sessionSigner} can spend up to ${spendingLimitWei} wei total (${perTxLimitWei} per tx) until block timestamp ${expiry}, restricted to ${allowedContracts.length} contract(s).`,
    securityNote: 'Vaultfire NEVER accepts private keys. Session keys are revocable on-chain via /actions/revoke-session-key. Use a fresh signer key for each session.',
    _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/create-session-key'), PAY_TO, {
  price: '$0.25', network: 'base',
  config: {
    description: 'Tx-prepare for VKPSessionKeyManager.createSession() — create a scoped, time-bounded session key with spending caps and a contract allowlist. Returns unsigned transaction; caller signs in wallet.',
    mimeType: 'application/json',
    outputSchema: {
      input: { type: 'http', method: 'POST', discoverable: true,
        bodySchema: {
          type: 'object', required: ['walletAddress', 'sessionSigner', 'expiry', 'spendingLimitWei', 'perTxLimitWei'],
          properties: {
            walletAddress: { type: 'string', description: 'Owner wallet that signs the create-session tx' },
            sessionSigner: { type: 'string', description: 'Address authorized as session signer' },
            expiry: { type: 'number', description: 'Unix timestamp at which the session expires' },
            spendingLimitWei: { type: 'string', description: 'Total spend cap in wei' },
            perTxLimitWei: { type: 'string', description: 'Per-tx spend cap in wei' },
            allowedContracts: { type: 'array', items: { type: 'string' }, description: 'Contracts the session signer may call' },
            chain: { type: 'string', enum: ['base', 'avalanche', 'arbitrum', 'polygon'], description: 'Chain (default: base)' },
          },
        },
      },
      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' } });
}
