/**
 * GET /api/agent/partnerships?address=0x...&chain=base
 *
 * Query partnership bonds for a given participant address from AIPartnershipBondsV2.
 * Returns a list of bonds with details (partner, amount, tier, status, type).
 */

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

// ABI function selectors for AIPartnershipBondsV2
const SELECTORS = {
  getBondsByParticipantCount: '0x8f601f66', // getBondsByParticipantCount(address) → uint256
  getBondsByParticipant: '0x5e615a57',       // getBondsByParticipant(address,uint256) → uint256 (bondId)
  getBond: '0x2d077ad4',                     // getBond(uint256) → (address,address,uint256,uint8,bool,string)
};

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 readWord(hex: string, wordIndex: number): string {
  const start = wordIndex * 64;
  return hex.slice(start, start + 64);
}

function getBondTier(weiHex: string): string {
  try {
    const wei = BigInt('0x' + weiHex);
    const eth = Number(wei) / 1e18;
    if (eth >= 0.5) return 'platinum';
    if (eth >= 0.1) return 'gold';
    if (eth >= 0.05) return 'silver';
    return 'bronze';
  } catch {
    return 'bronze';
  }
}

async function rpcCall(rpcUrl: string, to: string, data: string): Promise<string> {
  const res = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      id: 1,
      method: 'eth_call',
      params: [{ to, data }, 'latest'],
    }),
  });
  const json = await res.json();
  if (json.error) throw new Error(json.error.message || 'RPC error');
  return (json.result || '0x').replace('0x', '');
}

export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url);
    const address = searchParams.get('address');
    const chain = resolveChain(searchParams.get('chain')) as SupportedChain;

    // VF-015: Full Ethereum address validation (40 hex chars after 0x prefix)
    if (!address || !/^0x[a-fA-F0-9]{40}$/.test(address)) {
      return NextResponse.json({ error: 'Missing or invalid address' }, { status: 400 });
    }

    const bondContract = PARTNERSHIP_BONDS[chain];
    const rpcUrl = RPC_URLS[chain];

    if (!bondContract || !rpcUrl) {
      return NextResponse.json({ error: `Unsupported chain. Use one of: ${SUPPORTED_CHAINS.join(', ')} (or chain IDs: 8453, 43114, 42161, 137)` }, { status: 400 });
    }

    // Get bond count for this participant
    const countData = SELECTORS.getBondsByParticipantCount + encodeAddress(address);
    let countHex: string;
    try {
      countHex = await rpcCall(rpcUrl, bondContract, countData);
    } catch {
      return NextResponse.json({ bonds: [], count: 0 });
    }

    const bondCount = parseInt(countHex || '0', 16);
    if (bondCount === 0 || isNaN(bondCount)) {
      return NextResponse.json({ bonds: [], count: 0 });
    }

    // Fetch each bond (limit to 20 to avoid timeout)
    const maxBonds = Math.min(bondCount, 20);
    const bonds: { bondId: string; participant1: string; participant2: string; amount: string; tier: string; active: boolean; partnershipType: string; createdAt: string; }[] = [];

    for (let i = 0; i < maxBonds; i++) {
      try {
        // Get bond ID at index i
        const bondIdData = SELECTORS.getBondsByParticipant + encodeAddress(address) + encodeUint256(i);
        const bondIdHex = await rpcCall(rpcUrl, bondContract, bondIdData);
        const bondId = parseInt(bondIdHex || '0', 16);

        // Get bond details
        const bondData = SELECTORS.getBond + encodeUint256(bondId);
        const bondResult = await rpcCall(rpcUrl, bondContract, bondData);

        if (bondResult && bondResult.length >= 320) {
          const participant1 = '0x' + readWord(bondResult, 0).slice(24);
          const participant2 = '0x' + readWord(bondResult, 1).slice(24);
          const amountWeiHex = readWord(bondResult, 2);
          const amountWei = BigInt('0x' + amountWeiHex);
          const amountEth = (Number(amountWei) / 1e18).toFixed(4);
          const active = parseInt(readWord(bondResult, 4), 16) === 1;
          const tier = getBondTier(amountWeiHex);

          // Try to decode partnership type string
          let partnershipType = 'collaboration';
          try {
            const stringOffset = parseInt(readWord(bondResult, 5), 16) / 32;
            if (bondResult.length > (stringOffset + 1) * 64) {
              const stringLength = parseInt(readWord(bondResult, stringOffset), 16);
              if (stringLength > 0 && stringLength < 256) {
                const stringHex = bondResult.slice((stringOffset + 1) * 64, (stringOffset + 1) * 64 + stringLength * 2);
                const bytes: number[] = [];
                for (let j = 0; j < stringHex.length; j += 2) {
                  bytes.push(parseInt(stringHex.slice(j, j + 2), 16));
                }
                partnershipType = new TextDecoder().decode(new Uint8Array(bytes)) || 'collaboration';
              }
            }
          } catch {
            // Keep default
          }

          bonds.push({
            bondId: String(bondId),
            participant1,
            participant2,
            amount: amountEth,
            tier,
            active,
            partnershipType,
            createdAt: 'On-chain',
          });
        }
      } catch {
        // Skip failed bond reads
        continue;
      }
    }

    return NextResponse.json({
      bonds,
      count: bondCount,
      chain,
      contract: bondContract,
    });
  } catch (e) {
    return NextResponse.json({ error: 'Internal server error', bonds: [] }, { status: 500 });
  }
}
