/**
 * GET /api/x402/oracle/agent-stake-usd?address=0x...&chain=base — $0.02 USDC
 *
 * Composes two data sources:
 *   1) Vaultfire's on-chain agent bond data (bondAmountEth, bondCount, bondActive)
 *   2) Chainlink's decentralized price feed (ETH/USD or chain-native/USD)
 *
 * Returns the agent's TOTAL USD-DENOMINATED STAKE — a value neither Vaultfire
 * nor Chainlink could produce alone. Vaultfire owns the bond data, Chainlink
 * owns the price data; their composition is uniquely useful to agents pricing
 * x402 calls, validators sizing risk, and auditors scoring protocol health.
 *
 * Price conversion uses the native-token/USD feed for the queried chain:
 *   base       → ETH/USD   (bonds denominated in ETH on Base)
 *   avalanche  → AVAX/USD  (bonds denominated in AVAX on C-Chain)
 *   arbitrum   → ETH/USD   (bonds denominated in ETH on Arbitrum)
 *   polygon    → MATIC/USD (bonds denominated in MATIC/POL on Polygon)
 */

import { NextRequest, NextResponse } from 'next/server';
import { ethers } from 'ethers';
import { withX402 } from 'x402-next';
import { facilitator } from '@coinbase/x402';
import { withFailover } from '../../../_lib/rpc-retry';
import { FEEDS, AGGREGATOR_V3_ABI, type ChainKey, type PairKey } from '../_lib/feeds';

const PAY_TO = '0xfA15Ee28939B222B0448261A22156070f0A7813C';

/** Native-token price pair used for USD conversion, per chain. */
const NATIVE_PAIR: Record<ChainKey, PairKey> = {
  base: 'eth-usd',
  avalanche: 'avax-usd',
  arbitrum: 'eth-usd',
  polygon: 'matic-usd',
};

/** Human-readable native token symbol, per chain. */
const NATIVE_SYMBOL: Record<ChainKey, string> = {
  base: 'ETH',
  avalanche: 'AVAX',
  arbitrum: 'ETH',
  polygon: 'MATIC',
};

const handler = async (req: NextRequest) => {
  const { searchParams } = req.nextUrl;
  const address = searchParams.get('address');
  const chainParam = (searchParams.get('chain') || 'base').toLowerCase();

  if (!address) {
    return NextResponse.json({ error: 'address query parameter is required' }, { status: 400 });
  }
  if (!ethers.isAddress(address)) {
    return NextResponse.json({ error: 'Invalid address' }, { status: 400 });
  }
  if (!['base', 'avalanche', 'arbitrum', 'polygon'].includes(chainParam)) {
    return NextResponse.json({ error: 'Invalid chain. Use base|avalanche|arbitrum|polygon' }, { status: 400 });
  }
  const chain = chainParam as ChainKey;

  const nativePair = NATIVE_PAIR[chain];
  const feed = FEEDS[chain][nativePair];
  if (!feed) {
    // Shouldn't happen — every chain has its native feed mapped — but guard anyway.
    return NextResponse.json({ error: `No Chainlink native-token feed configured for ${chain}` }, { status: 500 });
  }

  try {
    // Fire both reads in parallel: Vaultfire hub (bond data) + Chainlink (price).
    const [hubRes, priceRoundData] = await Promise.all([
      fetch(`${req.nextUrl.origin}/api/agent/status?address=${encodeURIComponent(address)}&chain=${encodeURIComponent(chain)}`, {
        // Server-side fetch — don't cache, we want fresh bond state
        cache: 'no-store',
      }),
      withFailover(chain, async (provider) => {
        const c = new ethers.Contract(feed.address, AGGREGATOR_V3_ABI, provider);
        return (await c.latestRoundData()) as [bigint, bigint, bigint, bigint, bigint];
      }),
    ]);

    if (!hubRes.ok) {
      return NextResponse.json(
        { error: 'Failed to query Vaultfire agent status', detail: `hub returned ${hubRes.status}` },
        { status: 502 },
      );
    }
    const hubData = await hubRes.json();

    const [roundId, answerRaw, , updatedAt] = priceRoundData;
    const priceUsd = Number(answerRaw) / 10 ** feed.decimals;
    const bondAmountNative = typeof hubData.bondAmountEth === 'number' ? hubData.bondAmountEth : 0;
    const stakeUsd = bondAmountNative * priceUsd;

    const nowSec = Math.floor(Date.now() / 1000);
    const priceAgeSeconds = nowSec - Number(updatedAt);

    return NextResponse.json({
      address: address.toLowerCase(),
      chain,
      registered: Boolean(hubData.registered),
      hasBond: Boolean(hubData.hasBond),
      bondActive: Boolean(hubData.bondActive),
      bondCount: Number(hubData.bondCount ?? 0),
      // Native-token denominated (direct from Vaultfire on-chain state)
      stake: {
        amountNative: bondAmountNative,
        nativeSymbol: NATIVE_SYMBOL[chain],
      },
      // USD-denominated (Vaultfire bond × Chainlink price)
      stakeUsd: Number(stakeUsd.toFixed(4)),
      // Chainlink feed metadata — fully auditable
      priceFeed: {
        source: 'chainlink',
        pair: nativePair,
        address: feed.address,
        explorerUrl: feed.explorerUrl,
        priceUsd,
        decimals: feed.decimals,
        roundId: roundId.toString(),
        updatedAt: Number(updatedAt),
        ageSeconds: priceAgeSeconds,
        fresh: priceAgeSeconds >= 0 && priceAgeSeconds < 86400,
      },
      // Vaultfire agent context
      vaultfire: {
        vnsName: hubData.vnsName ?? null,
        trustScore: typeof hubData.trustScore === 'number' ? hubData.trustScore : null,
        explorerUrl: hubData.explorerUrl ?? null,
      },
      _x402: { paid: true, price: '$0.02 USDC', service: 'vaultfire-oracle', facilitator: 'cdp' },
      _composition: 'Vaultfire on-chain bond × Chainlink price feed. Neither source alone can compute this value.',
    }, { headers: { 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'no-store' } });
  } catch (e) {
    const err = e as { shortMessage?: string; message?: string };
    return NextResponse.json(
      { error: 'Failed to compose agent-stake-usd', detail: err?.shortMessage || err?.message || String(e) },
      { status: 502 },
    );
  }
};

// Canonical CDP paywall (matches actions/* family) — triggers CDP catalog auto-ingest.
export const GET = withX402(handler as (req: NextRequest) => Promise<NextResponse>, PAY_TO, {
  price: '$0.02', network: 'base',
  config: {
    description: 'Compute an agent\'s USD-denominated Vaultfire stake by combining Vaultfire\'s on-chain bond data (real ETH/AVAX/MATIC locked) with Chainlink\'s decentralized price feeds. Returns native-token stake, USD value, bond activity, and full Chainlink audit trail (feed address, roundId, updatedAt). Unique to Vaultfire × Chainlink.',
    mimeType: 'application/json',
    outputSchema: {
      input: { type: 'http', method: 'GET', discoverable: true,
        queryParams: {
          address: { type: 'string', description: 'Agent wallet address (0x...)' },
          chain: { type: 'string', description: 'Chain: base | avalanche | arbitrum | polygon (default: base)' },
        },
      },
      output: {
        type: 'object',
        properties: {
          address: { type: 'string' },
          chain: { type: 'string' },
          registered: { type: 'boolean' },
          hasBond: { type: 'boolean' },
          bondActive: { type: 'boolean' },
          bondCount: { type: 'number' },
          stake: { type: 'object' },
          stakeUsd: { type: 'number' },
          priceFeed: { type: 'object' },
          vaultfire: { type: 'object' },
        },
      },
    },
  },
}, facilitator);

export async function OPTIONS() {
  return new NextResponse(null, { status: 204, headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' } });
}
