/**
 * Allowlist registry for /api/x402/contract-call
 *
 * Builds a fast O(1) lookup of all 134 Vaultfire contracts by:
 *   - lowercased address (cross-chain)
 *   - chain + lowercased address  (most precise)
 *   - chain + name                 (human-readable alias)
 *
 * Read-only access only — state-changing functions are filtered at the
 * function-resolution layer (registry.ts only knows ABIs; mutability checks
 * live in `function-resolver.ts`).
 */

import {
  ALL_CONTRACTS,
  CHAINS,
  type SupportedChain,
} from '../../../../lib/contracts';

export type AllowlistEntry = {
  name: string;
  address: `0x${string}`;
  chain: SupportedChain;
  abi: readonly any[];
  rpcUrl: string;
  explorerUrl: string;
};

const byAddress: Map<string, AllowlistEntry> = new Map();        // "<chain>:<addr_lower>"
const byName: Map<string, AllowlistEntry> = new Map();           // "<chain>:<name_lower>"
const byAddressAnyChain: Map<string, AllowlistEntry> = new Map(); // "<addr_lower>" (first match wins)

for (const c of ALL_CONTRACTS) {
  const chain = c.chain as SupportedChain;
  const cfg = CHAINS[chain];
  if (!cfg) continue;

  const entry: AllowlistEntry = {
    name: c.name,
    address: c.address,
    chain,
    abi: c.abi as readonly any[],
    rpcUrl: cfg.rpcUrls.default.http[0],
    explorerUrl: cfg.explorerUrl,
  };

  const addrLower = c.address.toLowerCase();
  byAddress.set(`${chain}:${addrLower}`, entry);
  byName.set(`${chain}:${c.name.toLowerCase()}`, entry);
  if (!byAddressAnyChain.has(addrLower)) {
    byAddressAnyChain.set(addrLower, entry);
  }
}

export const TOTAL_ALLOWLISTED = ALL_CONTRACTS.length;

export function resolveContract(opts: {
  chain?: string;
  contract: string; // address OR name
}): AllowlistEntry | null {
  const target = opts.contract.trim();
  const chain = (opts.chain || '').toLowerCase();
  const targetLower = target.toLowerCase();

  // address path
  if (target.startsWith('0x') && target.length === 42) {
    if (chain) {
      return byAddress.get(`${chain}:${targetLower}`) ?? null;
    }
    return byAddressAnyChain.get(targetLower) ?? null;
  }

  // name path — chain required for unambiguous lookup, but we'll fall back to first-match
  if (chain) {
    return byName.get(`${chain}:${targetLower}`) ?? null;
  }
  // Try each chain
  for (const ch of ['base', 'avalanche', 'arbitrum', 'polygon'] as const) {
    const hit = byName.get(`${ch}:${targetLower}`);
    if (hit) return hit;
  }
  return null;
}

export function listSupportedChains(): SupportedChain[] {
  return ['base', 'avalanche', 'arbitrum', 'polygon'];
}
