/**
 * CMC and CoinGecko reporting API: all tokens, liquidity, volume, and reportable data.
 * Use for listing submissions and external aggregator sync.
 */

import { Router, Request, Response } from 'express';
import { existsSync, readFileSync } from 'fs';
import path from 'path';
import { TokenRepository } from '../../database/repositories/token-repo';
import { MarketDataRepository } from '../../database/repositories/market-data-repo';
import { PoolRepository } from '../../database/repositories/pool-repo';
import {
  CANONICAL_TOKENS,
  getCanonicalTokenByAddress,
  getCanonicalTokensByChain,
  getLogoUriForSpec,
  getTokenRegistryFamily,
} from '../../config/canonical-tokens';
import { resolvePoolTokenDisplays } from '../../services/token-display';
import { getSupportedChainIds } from '../../config/chains';
import { cacheMiddleware } from '../middleware/cache';
import { fetchRemoteJson } from '../utils/fetch-remote-json';
import { buildCrossChainReport } from '../../indexer/cross-chain-indexer';
import { logger } from '../../utils/logger';
import {
  filterPoolsForExposure,
  getActiveTransportPairs,
  getGruTransportMetadata,
  type GruTransportGasAssetFamily,
  type GruTransportPair,
} from '../../config/gru-transport';
import {
  buildCwRegistryChains,
  buildGasRegistryChains,
  loadDeploymentStatusFile,
  type DeploymentStatusFile,
  type CwRegistryChain,
} from '../../config/deployment-status';
import { getGruV2DeploymentPoolRows } from '../../config/gru-v2-deployment-pools';
import { getCanonicalPriceSnapshotGeneratedAt, getCanonicalPriceUsd } from '../../services/canonical-price-oracle';
import { getIso4217FxLastRefreshAt } from '../../services/iso4217-fx-refresh';
import { buildIso4217TokenListExtensions } from '../../services/iso4217-token-metadata';
import { pmmVaultReserveFromChain, resolvePmmQuoteRpcUrl } from '../../services/pmm-onchain-quote';
import {
  buildUniswapTokenList,
  MAINNET_PUBLIC_DISPLAY_NAMES,
  resolveTokenListName,
} from '../utils/uniswap-token-list';
import { buildCuratedPoolRegistry } from '../../services/pool-registry-report';
import { enrichCuratedPoolRegistryWithLiveLiquidity } from '../../services/pool-registry-enrichment';
import { buildLpPositionsReport } from '../../services/lp-positions-report';
import { isDeterministicPlaceholderAddress } from '../../lib/deterministic-placeholder-address';
import { isWalletWatchEligibleTokenAddress, isWalletWatchAssetEligible } from '../../lib/wallet-watch-eligible';

const router: Router = Router();
const tokenRepo = new TokenRepository();
const marketDataRepo = new MarketDataRepository();
const poolRepo = new PoolRepository();

const MAINNET_CWUSDC_ADDRESS = '0x2de5f116bfce3d0f922d9c8351e0c5fc24b9284a';
const DEFAULT_SUPPLY_CATALOG_RELATIVE_PATH = 'config/supply-proof-catalog.json';
const DEFAULT_LIVE_UNISWAP_V2_POOL_CATALOG_RELATIVE_PATH = 'config/live-uniswap-v2-pool-catalog.json';
const DEFAULT_PUBLIC_REPORT_BASE_URL = 'https://explorer.d-bis.org';
const DBIS_CHAIN_138_LOGO_PATH = '/api/v1/report/logo/chain-138';
const CWUSDC_SUPPLY_PROOF_FALLBACK = {
  schema: 'mainnet-cwusdc-supply-proof/v1',
  generatedAt: '2026-05-08T03:16:54Z',
  network: {
    chainId: 1,
    name: 'Ethereum Mainnet',
    referenceBlock: 25047586,
  },
  token: {
    address: MAINNET_CWUSDC_ADDRESS,
    name: 'Wrapped cUSDC',
    symbol: 'cWUSDC',
    decimals: 6,
    totalSupplyRaw: '10451316981309788',
    totalSupplyUnits: '10451316981.309788',
  },
  circulatingSupplyMethodology: {
    status: 'ready_for_tracker_review',
    recommendedFormula: 'circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances',
    currentConservativeReportableCirculatingSupplyUnits: '10451316981.309788',
    notes: [
      'No public tracker has accepted a circulating-supply value for this contract yet.',
      'If a tracker requires exclusion of operator, treasury, bridge, or protocol-controlled balances, use the knownBalances section plus any additional signed treasury inventory supplied at submission time.',
      'The value above is an on-chain supply proof, not a third-party listing approval.',
    ],
  },
};

type SupplyProofSnapshot = typeof CWUSDC_SUPPLY_PROOF_FALLBACK & {
  _sourcePath?: string;
  _source?: string;
};

type SupplyProofEnrichment = {
  totalSupply?: string;
  totalSupplyRaw?: string;
  circulatingSupply?: string;
  circulatingSupplyFormula?: string;
  marketCapUsd?: number;
  supplyProofProvenance: {
    source: string;
    path?: string;
    schema?: string;
    generatedAt?: string;
    referenceBlock?: number;
    status?: string;
  };
  trackerCaveats: string[];
};

type ReportPoolEntry = {
  poolAddress: string;
  dex: string;
  token0: string;
  token1: string;
  token0Symbol?: string;
  token1Symbol?: string;
  tvl: number;
  volume24h: number;
  source?: string;
  status?: string;
  statusReason?: string;
  role?: string;
  section?: string;
  publicRoutingEnabled?: boolean;
  reserveSource?: string;
  reserveUpdatedAt?: string;
  reserve0Raw?: string;
  reserve1Raw?: string;
};

type LiveUniswapV2PoolCatalogRow = {
  chainId: number;
  poolAddress: string;
  dex?: string;
  baseSymbol: string;
  quoteSymbol: string;
  baseAddress: string;
  quoteAddress: string;
  totalLiquidityUsd: number;
  reserve0Usd?: number;
  reserve1Usd?: number;
  depthOk?: boolean;
  parityOk?: boolean;
  healthy?: boolean;
  deviationBps?: string;
};

type LiveUniswapV2PoolCatalog = {
  schema?: string;
  generatedAt?: string;
  pools?: LiveUniswapV2PoolCatalogRow[];
};

function resolveRepoRoot(): string {
  const candidates = [
    process.env.PROXMOX_REPO_ROOT,
    process.env.PROJECT_ROOT,
    path.resolve(process.cwd(), '..', '..', '..'),
    path.resolve(process.cwd(), '..'),
    process.cwd(),
  ].filter(Boolean) as string[];

  for (const candidate of candidates) {
    if (
      existsSync(path.join(candidate, DEFAULT_SUPPLY_CATALOG_RELATIVE_PATH)) ||
      existsSync(path.join(candidate, DEFAULT_LIVE_UNISWAP_V2_POOL_CATALOG_RELATIVE_PATH)) ||
      existsSync(path.join(candidate, 'reports/status/mainnet-cwusdc-supply-proof-20260508.json'))
    ) {
      return candidate;
    }
  }
  return process.cwd();
}

/** Directories that may contain `config/live-uniswap-v2-pool-catalog.json` (package cwd or monorepo layouts). */
function resolveLiveUniswapPoolCatalogRoots(): string[] {
  const cwd = process.cwd();
  const nestedTa = path.join(cwd, 'smom-dbis-138', 'services', 'token-aggregation');
  const ordered = [
    cwd,
    ...(existsSync(path.join(nestedTa, DEFAULT_LIVE_UNISWAP_V2_POOL_CATALOG_RELATIVE_PATH)) ? [nestedTa] : []),
    path.resolve(cwd, '..', '..', '..'),
    path.resolve(cwd, '..'),
    process.env.PROXMOX_REPO_ROOT,
    process.env.PROJECT_ROOT,
  ].filter(Boolean) as string[];
  return [...new Set(ordered)];
}

function loadLiveUniswapV2PoolCatalog(): LiveUniswapV2PoolCatalogRow[] {
  const configuredCatalog = process.env.TOKEN_AGGREGATION_LIVE_UNISWAP_V2_POOL_CATALOG_JSON?.trim();
  const catalogCandidates = [
    configuredCatalog,
    ...resolveLiveUniswapPoolCatalogRoots().map((root) => path.join(root, DEFAULT_LIVE_UNISWAP_V2_POOL_CATALOG_RELATIVE_PATH)),
  ].filter(Boolean) as string[];

  for (const candidate of catalogCandidates) {
    if (!existsSync(candidate)) continue;
    try {
      const parsed = JSON.parse(readFileSync(candidate, 'utf8')) as LiveUniswapV2PoolCatalog;
      return (parsed.pools ?? []).filter(
        (pool) =>
          Number.isFinite(pool.chainId) &&
          pool.poolAddress?.startsWith('0x') &&
          pool.baseAddress?.startsWith('0x') &&
          pool.quoteAddress?.startsWith('0x')
      );
    } catch (error) {
      logger.warn('Unable to parse live Uniswap V2 pool catalog; skipping file', { candidate, error });
    }
  }

  return [];
}

function normalizeSupplyProofKey(chainId: number, address: string): string {
  return `${chainId}:${address.toLowerCase()}`;
}

function loadSupplyProofFile(proofPath: string, source: string): SupplyProofSnapshot[] {
  if (!proofPath || !existsSync(proofPath)) return [];

  try {
    const parsed = JSON.parse(readFileSync(proofPath, 'utf8')) as { proofs?: SupplyProofSnapshot[] } | SupplyProofSnapshot;
    const proofs: SupplyProofSnapshot[] = Array.isArray((parsed as { proofs?: SupplyProofSnapshot[] })?.proofs)
      ? ((parsed as { proofs: SupplyProofSnapshot[] }).proofs)
      : [parsed as SupplyProofSnapshot];
    return proofs
      .filter((proof) => proof?.network?.chainId && proof?.token?.address)
      .map((proof) => ({
        ...proof,
        _source: source,
        _sourcePath: proofPath,
      }));
  } catch (error) {
    logger.warn('Unable to parse supply proof file; skipping file', { proofPath, error });
    return [];
  }
}

function loadSupplyProofCatalog(): Map<string, SupplyProofSnapshot> {
  const configuredCatalog = process.env.TOKEN_AGGREGATION_SUPPLY_PROOF_CATALOG_JSON?.trim();
  const configuredSingleProof = process.env.CWUSDC_SUPPLY_PROOF_JSON?.trim();
  const repoRoot = resolveRepoRoot();
  const candidates = [
    configuredCatalog ? { path: configuredCatalog, source: 'configured-supply-proof-catalog' } : null,
    { path: path.join(repoRoot, DEFAULT_SUPPLY_CATALOG_RELATIVE_PATH), source: 'repo-supply-proof-catalog' },
    configuredSingleProof ? { path: configuredSingleProof, source: 'configured-supply-proof-file' } : null,
    { path: path.join(repoRoot, 'reports/status/mainnet-cwusdc-supply-proof-20260508.json'), source: 'repo-supply-proof-file' },
  ].filter(Boolean) as Array<{ path: string; source: string }>;

  const byToken = new Map<string, SupplyProofSnapshot>();
  for (const candidate of candidates) {
    for (const proof of loadSupplyProofFile(candidate.path, candidate.source)) {
      const key = normalizeSupplyProofKey(Number(proof.network.chainId), String(proof.token.address));
      if (!byToken.has(key)) {
        byToken.set(key, proof);
      }
    }
  }

  if (!byToken.has(normalizeSupplyProofKey(1, MAINNET_CWUSDC_ADDRESS))) {
    byToken.set(normalizeSupplyProofKey(1, MAINNET_CWUSDC_ADDRESS), {
      ...CWUSDC_SUPPLY_PROOF_FALLBACK,
      _source: 'embedded-fallback-snapshot',
    });
  }

  return byToken;
}

function isGruSupplyTrackedCandidate(symbol: string, type?: string, registryFamily?: string): boolean {
  return (
    /^c[A-Z0-9]/.test(symbol) &&
    (type === 'base' ||
      type === 'c' ||
      type === 'w' ||
      ['iso4217', 'monetary_unit', 'gas_native', 'commodity'].includes(String(registryFamily || '')))
  );
}

const EXTERNAL_OFFICIAL_QUOTE_ASSETS = new Set([
  '1:cUSDC:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
  '1:cUSDT:0xdac17f958d2ee523a2206206994597c13d831ec7',
  '10:cUSDC:0x0b2c639c533813f4aa9d7837caf62653d097ff85',
  '10:cUSDT:0x94b008aa00579c1307b0ef2c499ad98a8ce58e58',
  '25:cUSDC:0xc21223249ca28397b4b6541dffaecc539bff0c59',
  '25:cUSDT:0x66e428c3f67a68878562e79a0234c1f83c208770',
  '56:cUSDC:0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d',
  '56:cUSDT:0x55d398326f99059ff775485246999027b3197955',
  '100:cUSDC:0xddafbb505ad214d7b80b1f830fccc89b60fb7a83',
  '100:cUSDT:0x4ecaba5870353805a9f068101a40e0f32ed605c6',
  '137:cUSDC:0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
  '137:cUSDT:0xc2132d05d31c914a87c6611c10748aeb04b58e8f',
  '8453:cUSDC:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
  '8453:cUSDT:0xfde4c96c8593536e31f229ea8f37b2ada2699bb2',
  '42161:cUSDC:0xaf88d065e77c8cc2239327c5edb3a432268e5831',
  '42161:cUSDT:0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9',
  '42220:cUSDC:0xceba9300f2b948710d2653dd7b07f33a8b32118c',
  '42220:cUSDT:0x48065fbbe25f71c9282ddf5e1cd6d6a887483d5e',
  '43114:cUSDC:0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e',
  '43114:cUSDT:0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7',
  '1111:cUSDC:0xe3f5a90f9cb311505cd691a46596599aa1a0ad7d',
  '1111:cUSDT:0xa649325aa7c5093d12d6f98eb4378deae68ce23f',
  '651940:cUSDC:0xa95eed79f84e6a0151eaeb9d441f9ffd50e8e881',
  '651940:cUSDT:0x015b1897ed5279930bc2be46f661894d219292a6',
]);

function hasExternalOfficialQuoteLiquidity(token: { chainId: number; symbol: string; address: string }): boolean {
  return EXTERNAL_OFFICIAL_QUOTE_ASSETS.has(`${token.chainId}:${token.symbol}:${token.address.toLowerCase()}`);
}

function buildSupplyProofEnrichment(
  chainId: number,
  address: string,
  symbol: string,
  type: string | undefined,
  registryFamily: string | undefined,
  priceUsd?: number
): SupplyProofEnrichment | undefined {
  const proof = loadSupplyProofCatalog().get(normalizeSupplyProofKey(chainId, address));

  if (!proof) {
    if (!isGruSupplyTrackedCandidate(symbol, type, registryFamily)) return undefined;
    if (isDeterministicPlaceholderAddress(address)) {
      return {
        supplyProofProvenance: {
          source: 'deterministic-placeholder-address',
          status: 'non_reportable_until_erc20_deployed',
        },
        trackerCaveats: [
          'This token binding is a deterministic placeholder address and does not currently behave as an ERC-20 contract.',
          'Do not submit totalSupply, circulatingSupply, marketCapUsd, or liquidity claims for this asset until a deployed ERC-20 binding replaces the placeholder.',
          'The placeholder is kept visible for registry and routing roadmap traceability only.',
        ],
      };
    }
    return {
      supplyProofProvenance: {
        source: 'missing-supply-proof',
        status: 'proof_required',
      },
      trackerCaveats: [
        'No token-specific on-chain supply proof artifact is currently attached to this report response.',
        'Do not submit totalSupply, circulatingSupply, or marketCapUsd for this asset until a current proof artifact is generated and linked.',
        'Registry and pool visibility are not the same as tracker-grade supply proof.',
      ],
    };
  }

  const totalSupply = String(proof.token?.totalSupplyUnits ?? '');
  const totalSupplyRaw = String(proof.token?.totalSupplyRaw ?? '');
  const circulatingSupply = String(
    proof.circulatingSupplyMethodology?.currentConservativeReportableCirculatingSupplyUnits ?? totalSupply
  );
  const parsedCirculatingSupply = Number(circulatingSupply);
  const marketCapUsd =
    priceUsd !== undefined && Number.isFinite(parsedCirculatingSupply) ? parsedCirculatingSupply * priceUsd : undefined;

  return {
    totalSupply,
    totalSupplyRaw,
    circulatingSupply,
    circulatingSupplyFormula: String(
      proof.circulatingSupplyMethodology?.recommendedFormula ??
        'circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances'
    ),
    marketCapUsd,
    supplyProofProvenance: {
      source: proof._source ?? 'repo-supply-proof-file',
      path: proof._sourcePath,
      schema: proof.schema,
      generatedAt: proof.generatedAt,
      referenceBlock: proof.network?.referenceBlock,
      status: proof.circulatingSupplyMethodology?.status,
    },
    trackerCaveats: proof.circulatingSupplyMethodology?.notes ?? [
      'Tracker acceptance is external and not implied by this API response.',
    ],
  };
}

function normalizePossiblyRawLiquidityUsd(
  liquidityUsd: number | undefined,
  decimals: number,
  priceUsd: number | undefined,
  totalSupplyUnits: string | undefined
): number | undefined {
  if (liquidityUsd === undefined || !Number.isFinite(liquidityUsd) || liquidityUsd <= 0) return liquidityUsd;
  if (priceUsd === undefined || !Number.isFinite(priceUsd) || priceUsd <= 0) return liquidityUsd;
  if (!totalSupplyUnits) {
    if (decimals === 6 && liquidityUsd >= 1_000_000_000_000 && priceUsd <= 10) {
      return liquidityUsd / 10 ** decimals;
    }
    return liquidityUsd;
  }

  const supplyUnits = Number(totalSupplyUnits);
  if (!Number.isFinite(supplyUnits) || supplyUnits <= 0) return liquidityUsd;

  const normalizedSupplyValue = supplyUnits * priceUsd;
  const divisor = 10 ** decimals;
  const decimalAdjustedLiquidity = liquidityUsd / divisor;

  if (
    liquidityUsd > normalizedSupplyValue &&
    decimalAdjustedLiquidity > 0 &&
    decimalAdjustedLiquidity <= normalizedSupplyValue * 1.25
  ) {
    return decimalAdjustedLiquidity;
  }

  return liquidityUsd;
}

function resolveGruV2ReserveRpcUrl(chainId: number): string {
  const configured = resolvePmmQuoteRpcUrl();
  if (chainId === 138 && process.env.NODE_ENV !== 'test') return configured || 'http://192.168.11.211:8545';
  if (chainId === 56 && process.env.NODE_ENV !== 'test') {
    return process.env.BSC_RPC_URL || process.env.BSC_MAINNET_RPC || process.env.RPC_URL_56 || 'https://bsc-rpc.publicnode.com';
  }
  if (chainId === 43114 && process.env.NODE_ENV !== 'test') {
    return (
      process.env.AVALANCHE_RPC_URL ||
      process.env.AVALANCHE_MAINNET_RPC ||
      process.env.RPC_URL_43114 ||
      'https://avalanche-c-chain-rpc.publicnode.com'
    );
  }
  if (chainId === 1111 && process.env.NODE_ENV !== 'test') {
    return process.env.WEMIX_MAINNET_RPC || process.env.WEMIX_RPC || process.env.RPC_URL_1111 || 'https://api.wemix.com';
  }
  return '';
}

function decimalFromRawForReport(raw: bigint, decimals: number): number {
  const scale = 10 ** decimals;
  return Number(raw) / scale;
}

function fallbackPoolDecimals(symbol?: string): number {
  const normalized = String(symbol || '').toUpperCase();
  if (normalized === 'WETH' || normalized === 'ETH') return 18;
  return 6;
}

function fallbackPoolUsdPrice(symbol?: string): number {
  const normalized = String(symbol || '').toUpperCase();
  if (normalized.includes('XAU')) return Number(process.env.TOKEN_AGGREGATION_XAU_USD || '0') || 0;
  if (normalized === 'WETH' || normalized === 'ETH') return Number(process.env.TOKEN_AGGREGATION_ETH_USD || '0') || 0;
  return 1;
}

async function enrichGruV2FallbackPoolWithReserves(chainId: number, pool: ReportPoolEntry): Promise<ReportPoolEntry> {
  const rpcUrl = resolveGruV2ReserveRpcUrl(chainId);
  if (!rpcUrl) return pool;

  const reserves = await pmmVaultReserveFromChain({ rpcUrl, poolAddress: pool.poolAddress });
  if (!reserves) return pool;

  const baseUnits = decimalFromRawForReport(reserves.baseReserveRaw, fallbackPoolDecimals(pool.token0Symbol));
  const quoteUnits = decimalFromRawForReport(reserves.quoteReserveRaw, fallbackPoolDecimals(pool.token1Symbol));
  const reserveUsd =
    baseUnits * fallbackPoolUsdPrice(pool.token0Symbol) + quoteUnits * fallbackPoolUsdPrice(pool.token1Symbol);

  if (!Number.isFinite(reserveUsd) || reserveUsd <= 0) {
    return {
      ...pool,
      reserveSource: 'onchain-gru-v2-pmm-getVaultReserve',
      reserveUpdatedAt: new Date().toISOString(),
      reserve0Raw: reserves.baseReserveRaw.toString(),
      reserve1Raw: reserves.quoteReserveRaw.toString(),
    };
  }

  return {
    ...pool,
    tvl: reserveUsd,
    status: pool.status ?? 'reserve_visible',
    statusReason:
      pool.statusReason ??
      'Pool is present in deployment-status and has positive on-chain reserves via getVaultReserve().',
    reserveSource: 'onchain-gru-v2-pmm-getVaultReserve',
    reserveUpdatedAt: new Date().toISOString(),
    reserve0Raw: reserves.baseReserveRaw.toString(),
    reserve1Raw: reserves.quoteReserveRaw.toString(),
  };
}

async function buildGruV2FallbackPoolsForToken(
  chainId: number,
  tokenAddress: string,
  existingPools: ReportPoolEntry[]
): Promise<ReportPoolEntry[]> {
  const token = tokenAddress.toLowerCase();
  const existing = new Set(existingPools.map((pool) => pool.poolAddress.toLowerCase()));
  const pools = getGruV2DeploymentPoolRows()
    .filter((pool) => pool.chainId === chainId)
    .filter((pool) => pool.baseAddress.toLowerCase() === token || pool.quoteAddress.toLowerCase() === token)
    .filter((pool) => !existing.has(pool.poolAddress.toLowerCase()))
    .map((pool) => ({
      poolAddress: pool.poolAddress,
      dex: pool.venue ?? 'gru_v2_pmm',
      token0: pool.baseAddress,
      token1: pool.quoteAddress,
      token0Symbol: pool.baseSymbol,
      token1Symbol: pool.quoteSymbol,
      tvl: 0,
      volume24h: 0,
      source: 'gru-v2-deployment-status',
      status: pool.status,
      statusReason: pool.statusReason,
      role: pool.role,
      section: pool.section,
      publicRoutingEnabled: pool.publicRoutingEnabled,
    }));

  return Promise.all(pools.map((pool) => enrichGruV2FallbackPoolWithReserves(chainId, pool)));
}

/** Prefer live catalog USD TVL when DB or repo-fallback rows carry the same pool with lower TVL. */
function mergeLiveUniswapCatalogTvlIntoPools(chainId: number, pools: ReportPoolEntry[]): ReportPoolEntry[] {
  const catalog = loadLiveUniswapV2PoolCatalog();
  const byPool = new Map(
    catalog.filter((row) => row.chainId === chainId).map((row) => [row.poolAddress.toLowerCase(), row])
  );
  return pools.map((pool) => {
    const row = byPool.get(pool.poolAddress.toLowerCase());
    if (!row) return pool;
    const catalogUsd = Number(row.totalLiquidityUsd ?? 0);
    if (!Number.isFinite(catalogUsd) || catalogUsd <= (pool.tvl || 0)) {
      return pool;
    }
    const note =
      'Live Uniswap V2 pool catalog totalLiquidityUsd merged over lower indexed DB or repo-fallback TVL.';
    return {
      ...pool,
      tvl: catalogUsd,
      statusReason: pool.statusReason ? `${pool.statusReason} ${note}` : note,
    };
  });
}

function buildLiveUniswapV2FallbackPoolsForToken(
  chainId: number,
  tokenAddress: string,
  existingPools: ReportPoolEntry[]
): ReportPoolEntry[] {
  const token = tokenAddress.toLowerCase();
  const existing = new Set(existingPools.map((pool) => pool.poolAddress.toLowerCase()));
  return loadLiveUniswapV2PoolCatalog()
    .filter((pool) => pool.chainId === chainId)
    .filter((pool) => pool.baseAddress.toLowerCase() === token || pool.quoteAddress.toLowerCase() === token)
    .filter((pool) => !existing.has(pool.poolAddress.toLowerCase()))
    .map((pool) => ({
      poolAddress: pool.poolAddress,
      dex: pool.dex ?? 'uniswap_v2',
      token0: pool.baseAddress,
      token1: pool.quoteAddress,
      token0Symbol: pool.baseSymbol,
      token1Symbol: pool.quoteSymbol,
      tvl: Number(pool.totalLiquidityUsd ?? 0),
      volume24h: 0,
      source: 'live-uniswap-v2-pair-discovery',
      status: pool.healthy ? 'indexed_live_healthy' : 'indexed_live_needs_repair',
      statusReason: pool.healthy
        ? 'Live Uniswap V2 pair discovered with on-chain reserves, depth, and parity checks passing.'
        : `Live Uniswap V2 pair discovered; depthOk=${pool.depthOk === true}, parityOk=${pool.parityOk === true}, deviationBps=${pool.deviationBps ?? 'unknown'}.`,
      role: 'public_indexable_liquidity',
      publicRoutingEnabled: pool.healthy === true,
    }));
}

function resolveLocalLogoUri(remoteLogoUri: string, symbol: string): string | undefined {
  if (/^https:\/\/d-bis\.org\//i.test(remoteLogoUri)) {
    return undefined;
  }
  if (remoteLogoUri.startsWith('/api/v1/report/logo/')) {
    return remoteLogoUri;
  }
  if (remoteLogoUri.includes('/token-lists/logos/gru/')) {
    const fileName = remoteLogoUri.split('/').pop()?.replace(/\.svg$/i, '');
    return fileName ? `/api/v1/report/logo/${fileName}` : undefined;
  }
  if (remoteLogoUri.includes('/blockchains/bitcoin/info/logo.png')) {
    return '/api/v1/report/logo/cWBTC';
  }
  if (remoteLogoUri.includes('/ipfs/')) {
    const cid = remoteLogoUri.split('/').pop();
    return cid ? `/api/v1/report/logo/ipfs-${cid}` : undefined;
  }
  if (symbol === 'cWUSDC') {
    return '/api/v1/report/logo/cUSDC';
  }
  return undefined;
}

function resolvePublicBaseUrl(req: Request): string {
  const configured = (
    process.env.TOKEN_AGGREGATION_PUBLIC_BASE_URL ??
    process.env.PUBLIC_API_BASE_URL ??
    process.env.PUBLIC_BASE_URL ??
    ''
  ).trim();
  if (configured) return configured.replace(/\/+$/, '');

  const host = String(req.get('x-forwarded-host') || req.get('host') || '').split(',')[0].trim();
  if (host) {
    let proto = String(req.get('x-forwarded-proto') || 'https').split(',')[0].trim() || 'https';
    if (proto === 'http' && !/^(localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/i.test(host)) {
      proto = 'https';
    }
    return `${proto}://${host}`.replace(/\/+$/, '');
  }

  return DEFAULT_PUBLIC_REPORT_BASE_URL;
}

function absolutePublicUrl(req: Request, value: string | undefined): string | undefined {
  if (!value) return undefined;
  if (/^https?:\/\//i.test(value)) return value;
  if (!value.startsWith('/')) return value;
  return `${resolvePublicBaseUrl(req)}${value}`;
}

function absoluteLogoUri(req: Request, remoteLogoUri: string, symbol: string): string {
  const localLogoURI = resolveLocalLogoUri(remoteLogoUri, symbol);
  return absolutePublicUrl(req, localLogoURI) ?? remoteLogoUri;
}

function absoluteReportLogoUri(remoteLogoUri: string, symbol: string): string {
  const localLogoURI = resolveLocalLogoUri(remoteLogoUri, symbol);
  if (localLogoURI?.startsWith('/')) return `${DEFAULT_PUBLIC_REPORT_BASE_URL}${localLogoURI}`;
  return localLogoURI ?? remoteLogoUri;
}

function resolveEthereumMainnetTokenListPath(): string | null {
  const candidates = [
    process.env.ETHEREUM_MAINNET_TOKEN_LIST_JSON_PATH?.trim(),
    path.join(__dirname, '../../../config/token-lists/ethereum-mainnet.tokenlist.json'),
    path.join(process.cwd(), 'config/token-lists/ethereum-mainnet.tokenlist.json'),
  ].filter((value): value is string => Boolean(value));

  for (const candidate of candidates) {
    if (existsSync(candidate)) return candidate;
  }
  return null;
}

function loadStaticEthereumMainnetTokenList(): Record<string, unknown> | null {
  const filePath = resolveEthereumMainnetTokenListPath();
  if (!filePath) return null;
  try {
    return JSON.parse(readFileSync(filePath, 'utf8')) as Record<string, unknown>;
  } catch (error) {
    logger.error('Failed to read static ethereum-mainnet token list:', error);
    return null;
  }
}

function resolveDbis138TokenListPath(): string | null {
  const candidates = [
    process.env.DBIS_138_TOKEN_LIST_JSON_PATH?.trim(),
    process.env.TOKEN_LIST_JSON_PATH?.trim(),
  ].filter((value): value is string => Boolean(value));

  if (process.env.NODE_ENV !== 'test') {
    candidates.push(
      path.join(__dirname, '../../../config/token-lists/dbis-138.tokenlist.json'),
      path.join(process.cwd(), 'config/token-lists/dbis-138.tokenlist.json'),
      '/opt/token-aggregation/config/token-lists/dbis-138.tokenlist.json'
    );
  }

  for (const candidate of candidates) {
    if (existsSync(candidate)) return candidate;
  }
  return null;
}

function loadDbis138TokenListFromFile(): Record<string, unknown> | null {
  const filePath = resolveDbis138TokenListPath();
  if (!filePath) return null;
  try {
    return JSON.parse(readFileSync(filePath, 'utf8')) as Record<string, unknown>;
  } catch (error) {
    logger.error('Failed to read dbis-138 token list:', error);
    return null;
  }
}

function finalizeUniswapTokenListResponse(
  req: Request,
  res: Response,
  payload: Record<string, unknown>,
  chainIds: number[],
  options?: { walletEligibleOnly?: boolean },
): void {
  const logoURI = absolutePublicUrl(req, typeof payload.logoURI === 'string' ? payload.logoURI : undefined);
  const walletEligibleOnly = options?.walletEligibleOnly === true;
  const tokens = Array.isArray(payload.tokens)
    ? payload.tokens
        .map((token) => {
          const record = token as Record<string, unknown>;
          const address = typeof record.address === 'string' ? record.address : undefined;
          const walletWatchEligible = isWalletWatchEligibleTokenAddress(address);
          const chainId = typeof record.chainId === 'number' ? record.chainId : undefined;
          const spec =
            chainId && address ? getCanonicalTokenByAddress(chainId, address) : undefined;
          const iso4217Extensions = spec ? buildIso4217TokenListExtensions(spec) : {};
          const extensions =
            record.extensions && typeof record.extensions === 'object' && !Array.isArray(record.extensions)
              ? (record.extensions as Record<string, unknown>)
              : {};
          return {
            ...record,
            logoURI:
              absolutePublicUrl(req, typeof record.logoURI === 'string' ? record.logoURI : undefined) ??
              record.logoURI,
            extensions: {
              ...iso4217Extensions,
              ...extensions,
              walletWatchEligible,
            },
          };
        })
        .filter((token) => {
          if (!walletEligibleOnly) return true;
          const record = token as Record<string, unknown>;
          const address = typeof record.address === 'string' ? record.address : undefined;
          if (!isWalletWatchEligibleTokenAddress(address)) return false;
          const extensions =
            record.extensions && typeof record.extensions === 'object' && !Array.isArray(record.extensions)
              ? (record.extensions as Record<string, unknown>)
              : {};
          const status = String(extensions.deploymentStatus || '').toLowerCase();
          const version = String(extensions.deploymentVersion || '').toLowerCase();
          const familySymbol = extensions.familySymbol;
          if (status === 'staged' || (version === 'v2' && familySymbol)) return false;
          return true;
        })
    : [];

  const displayNames = chainIds.length === 1 && chainIds[0] === 1 ? MAINNET_PUBLIC_DISPLAY_NAMES : undefined;
  const body = buildUniswapTokenList({
    name: resolveTokenListName(
      chainIds,
      typeof payload.name === 'string' ? payload.name : 'GRU Canonical Token List'
    ),
    version: payload.version,
    timestamp: typeof payload.timestamp === 'string' ? payload.timestamp : new Date().toISOString(),
    logoURI,
    tokens,
    keywords: Array.isArray(payload.keywords) ? (payload.keywords as string[]) : undefined,
    tags:
      payload.tags && typeof payload.tags === 'object' && !Array.isArray(payload.tags)
        ? (payload.tags as Record<string, unknown>)
        : undefined,
    displayNames,
  });

  res.json(body);
}

/** Build token entries with DB market/pool data for a chain */
async function buildTokenReport(chainId: number) {
  const canonical = getCanonicalTokensByChain(chainId);
  const out: Array<{
    chainId: number;
    address: string;
    symbol: string;
    name: string;
    type: string;
    decimals: number;
    currencyCode?: string;
    registryFamily?: string;
    familySymbol?: string;
    deploymentVersion?: string;
    deploymentStatus?: string;
    preferredForX402?: boolean;
    liquiditySourceSymbol?: string;
    logoURI?: string;
    originalLogoURI?: string;
    market?: {
      priceUsd?: number;
      volume24h: number;
      volume7d: number;
      volume30d: number;
      marketCapUsd?: number;
      liquidityUsd: number;
      lastUpdated: string;
    };
    totalSupply?: string;
    totalSupplyRaw?: string;
    circulatingSupply?: string;
    circulatingSupplyFormula?: string;
    supplyProofProvenance?: SupplyProofEnrichment['supplyProofProvenance'];
    trackerCaveats?: string[];
    pools: ReportPoolEntry[];
    fromDb: boolean;
  }> = [];

  for (const spec of canonical) {
    const address = spec.addresses[chainId];
    if (!address || String(address).trim() === '') continue;

    const [dbToken, marketData, pools] = await Promise.all([
      tokenRepo.getToken(chainId, address),
      marketDataRepo.getMarketData(chainId, address),
      poolRepo.getPoolsByToken(chainId, address),
    ]);
    const exposedPools = filterPoolsForExposure(chainId, pools);

    const resolvedPools = await Promise.all(
      exposedPools.map(async (p) => {
        const { token0, token1 } = await resolvePoolTokenDisplays(tokenRepo, chainId, p.token0Address, p.token1Address);
        return {
          poolAddress: p.poolAddress,
          dex: p.dexType,
          token0,
          token1,
          tvl: p.totalLiquidityUsd,
          volume24h: p.volume24h,
        };
      })
    );

    const fallbackPriceUsd = getCanonicalPriceUsd(chainId, address);

    const market = marketData
      ? {
          priceUsd: marketData.priceUsd ?? fallbackPriceUsd,
          volume24h: marketData.volume24h,
          volume7d: marketData.volume7d,
          volume30d: marketData.volume30d,
          marketCapUsd: marketData.marketCapUsd,
          liquidityUsd: marketData.liquidityUsd,
          lastUpdated: marketData.lastUpdated?.toISOString() ?? '',
        }
      : fallbackPriceUsd !== undefined
        ? {
            priceUsd: fallbackPriceUsd,
            volume24h: 0,
            volume7d: 0,
            volume30d: 0,
            liquidityUsd: 0,
            lastUpdated: `${getCanonicalPriceSnapshotGeneratedAt()}T00:00:00.000Z`,
          }
        : undefined;
    const registryFamily = getTokenRegistryFamily(spec);
    const originalLogoURI = getLogoUriForSpec(spec);
    const logoURI = absoluteReportLogoUri(originalLogoURI, spec.symbol);
    const supplyProof = buildSupplyProofEnrichment(chainId, address, spec.symbol, spec.type, registryFamily, market?.priceUsd);
    if (supplyProof?.marketCapUsd !== undefined && market) {
      market.marketCapUsd = supplyProof.marketCapUsd;
    }
    if (market) {
      market.liquidityUsd =
        normalizePossiblyRawLiquidityUsd(market.liquidityUsd, spec.decimals, market.priceUsd, supplyProof?.totalSupply) ??
        market.liquidityUsd;
    }

    const dbPoolEntries: ReportPoolEntry[] = resolvedPools.map((p) => ({
      poolAddress: p.poolAddress,
      dex: p.dex,
      token0: p.token0.address,
      token1: p.token1.address,
      token0Symbol: p.token0.symbol,
      token1Symbol: p.token1.symbol,
      tvl: p.tvl,
      volume24h: p.volume24h,
      source: 'indexed-db',
      status: 'indexed',
      statusReason: 'Pool is present in the token-aggregation indexed pool repository.',
    }));
    const liveUniswapV2PoolEntries = buildLiveUniswapV2FallbackPoolsForToken(chainId, address, dbPoolEntries);
    const gruV2FallbackPoolEntries = await buildGruV2FallbackPoolsForToken(chainId, address, [
      ...dbPoolEntries,
      ...liveUniswapV2PoolEntries,
    ]);
    const reportPools = mergeLiveUniswapCatalogTvlIntoPools(chainId, [
      ...dbPoolEntries,
      ...liveUniswapV2PoolEntries,
      ...gruV2FallbackPoolEntries,
    ]);

    const poolTvlSum = reportPools.reduce((sum, p) => sum + (Number.isFinite(p.tvl) ? p.tvl : 0), 0);
    if (market && poolTvlSum > (market.liquidityUsd ?? 0)) {
      market.liquidityUsd = poolTvlSum;
    }

    out.push({
      chainId,
      address: address.toLowerCase(),
      symbol: spec.symbol,
      name: dbToken?.name ?? spec.name,
      type: spec.type,
      decimals: spec.decimals,
      currencyCode: spec.currencyCode,
      registryFamily,
      familySymbol: spec.familySymbol,
      deploymentVersion: spec.deploymentVersion,
      deploymentStatus: spec.deploymentStatus,
      preferredForX402: spec.preferredForX402,
      liquiditySourceSymbol: spec.liquiditySourceSymbol,
      logoURI,
      originalLogoURI,
      market,
      totalSupply: supplyProof?.totalSupply,
      totalSupplyRaw: supplyProof?.totalSupplyRaw,
      circulatingSupply: supplyProof?.circulatingSupply,
      circulatingSupplyFormula: supplyProof?.circulatingSupplyFormula,
      supplyProofProvenance: supplyProof?.supplyProofProvenance,
      trackerCaveats: supplyProof?.trackerCaveats,
      pools: reportPools,
      fromDb: !!dbToken,
    });
  }

  return out;
}

function describeToken(spec: { currencyCode?: string; registryFamily?: string }): string | undefined {
  const family = String(spec.registryFamily || '').trim();
  const code = String(spec.currencyCode || '').trim().toUpperCase();
  if (!code) return undefined;
  if (family === 'gas_native') {
    return `Governance-approved gas-native ${code} compliant token`;
  }
  if (family === 'monetary_unit') {
    return `GRU monetary-unit ${code} compliant token`;
  }
  if (family === 'commodity') {
    return `Governance-approved commodity ${code} compliant token`;
  }
  return `ISO-4217 ${code} compliant token`;
}

function buildGruTransportOverview() {
  const gruTransportMetadata = getGruTransportMetadata();
  const deploymentStatus = loadDeploymentStatusFile()?.data;

  if (!gruTransportMetadata && !deploymentStatus) return undefined;

  const activeTransportPairs = getActiveTransportPairs();
  const fallbackGasAssetFamilies = deploymentStatus ? buildGasAssetFamiliesFromDeploymentStatus(deploymentStatus) : [];
  const fallbackRuntimePairs = deploymentStatus ? buildGasRuntimePairsFromDeploymentStatus(deploymentStatus) : [];
  const gasAssetFamilies = gruTransportMetadata?.gasAssetFamilies ?? fallbackGasAssetFamilies;
  const gasRedeemGroups = gruTransportMetadata?.gasRedeemGroups ?? [];
  const gasProtocolExposure = gruTransportMetadata?.gasProtocolExposure ?? [];
  const runtimePairs = activeTransportPairs.length > 0 ? activeTransportPairs : fallbackRuntimePairs;

  return {
    system: gruTransportMetadata?.system ?? {
      name: 'GRU Monetary Transport Layer',
      shortName: 'GRU Transport',
      canonicalChainId: 138,
      canonicalChainName: 'DeFi Oracle Meta Chain 138',
      transportClass: 'deployment-status-fallback',
    },
    summary: gruTransportMetadata?.counts ?? {
      enabledCanonicalTokens: 0,
      enabledDestinationChains: new Set(runtimePairs.map((pair) => pair.destinationChainId)).size,
      approvedBridgePeers: 0,
      transportPairs: runtimePairs.length,
      gasAssetFamilies: gasAssetFamilies.length,
      gasRedeemGroups: gasRedeemGroups.length,
      gasProtocolExposure: gasProtocolExposure.length,
      gasTransportPairs: runtimePairs.length,
      runtimeReadyTransportPairs: runtimePairs.filter((pair) => pair.runtimeReady === true).length,
      publicPools: 0,
    },
    gasAssetFamilies,
    gasRedeemGroups,
    gasProtocolExposure,
    activeTransportPairs: runtimePairs.map((pair) => ({
      key: pair.key,
      canonicalSymbol: pair.canonicalSymbol,
      mirroredSymbol: pair.mirroredSymbol,
      destinationChainId: pair.destinationChainId,
      destinationChainName: pair.destinationChainName ?? null,
      assetClass: pair.assetClass,
      familyKey: pair.familyKey,
      backingMode: pair.backingMode,
      redeemPolicy: pair.redeemPolicy,
      wrappedNativeQuoteSymbol: pair.wrappedNativeQuoteSymbol ?? null,
      stableQuoteSymbol: pair.stableQuoteSymbol ?? null,
      eligible: pair.eligible === true,
      runtimeReady: pair.runtimeReady === true,
      supplyInvariantSatisfied: pair.supplyInvariantSatisfied ?? null,
      eligibilityBlockers: Array.isArray(pair.eligibilityBlockers)
        ? pair.eligibilityBlockers
        : [],
      runtimeMissingRequirements: Array.isArray(pair.runtimeMissingRequirements)
        ? pair.runtimeMissingRequirements
        : [],
    })),
  };
}

function gasFamilyDefaults(familyKey: string, mirroredSymbol: string) {
  const byFamily: Record<string, { canonicalSymbol138: string; assetClass: string; backingMode: string; redeemPolicy: string; laneGroup: string }> = {
    eth_mainnet: {
      canonicalSymbol138: 'cETH',
      assetClass: 'gas_native',
      backingMode: 'strict_escrow',
      redeemPolicy: 'same_family_only',
      laneGroup: 'eth_mainnet',
    },
    eth_l2: {
      canonicalSymbol138: 'cETHL2',
      assetClass: 'gas_native',
      backingMode: 'hybrid_cap',
      redeemPolicy: 'same_family_only',
      laneGroup: 'eth_l2',
    },
    bnb: {
      canonicalSymbol138: 'cBNB',
      assetClass: 'gas_native',
      backingMode: 'strict_escrow',
      redeemPolicy: 'same_family_only',
      laneGroup: 'bnb',
    },
    pol: {
      canonicalSymbol138: 'cPOL',
      assetClass: 'gas_native',
      backingMode: 'strict_escrow',
      redeemPolicy: 'same_family_only',
      laneGroup: 'pol',
    },
    avax: {
      canonicalSymbol138: 'cAVAX',
      assetClass: 'gas_native',
      backingMode: 'strict_escrow',
      redeemPolicy: 'same_family_only',
      laneGroup: 'avax',
    },
    cro: {
      canonicalSymbol138: 'cCRO',
      assetClass: 'gas_native',
      backingMode: 'strict_escrow',
      redeemPolicy: 'same_family_only',
      laneGroup: 'cro',
    },
    xdai: {
      canonicalSymbol138: 'cXDAI',
      assetClass: 'gas_native',
      backingMode: 'strict_escrow',
      redeemPolicy: 'same_family_only',
      laneGroup: 'xdai',
    },
    celo: {
      canonicalSymbol138: 'cCELO',
      assetClass: 'gas_native',
      backingMode: 'strict_escrow',
      redeemPolicy: 'same_family_only',
      laneGroup: 'celo',
    },
    wemix: {
      canonicalSymbol138: 'cWEMIX',
      assetClass: 'gas_native',
      backingMode: 'strict_escrow',
      redeemPolicy: 'same_family_only',
      laneGroup: 'wemix',
    },
  };

  return byFamily[familyKey] ?? {
    canonicalSymbol138: mirroredSymbol.replace(/^cW/, 'c'),
    assetClass: 'gas_native',
    backingMode: 'strict_escrow',
    redeemPolicy: 'same_family_only',
    laneGroup: familyKey,
  };
}

function buildGasAssetFamiliesFromDeploymentStatus(data: DeploymentStatusFile): GruTransportGasAssetFamily[] {
  const byFamily = new Map<string, GruTransportGasAssetFamily>();

  for (const [chainIdText, chain] of Object.entries(data.chains ?? {})) {
    const chainId = Number(chainIdText);
    for (const pool of chain.gasPmmPools ?? []) {
      const familyKey = typeof pool.familyKey === 'string' ? pool.familyKey : '';
      const mirroredSymbol = typeof pool.base === 'string' ? pool.base : '';
      if (!familyKey || !mirroredSymbol) continue;
      const defaults = gasFamilyDefaults(familyKey, mirroredSymbol);
      const existing = byFamily.get(familyKey) ?? {
        familyKey,
        active: true,
        status: 'deployment_status_fallback',
        canonicalSymbol138: defaults.canonicalSymbol138,
        mirroredSymbol,
        assetClass: defaults.assetClass,
        originChains: [],
        laneGroup: defaults.laneGroup,
        backingMode: defaults.backingMode,
        redeemPolicy: defaults.redeemPolicy,
        wrappedNativeQuoteSymbol: 'WETH',
        stableQuoteSymbol: 'USDC',
        referenceVenue: 'deployment-status',
      };
      if (!existing.originChains.includes(chainId)) {
        existing.originChains.push(chainId);
      }
      if (typeof pool.quote === 'string' && ['WETH', 'WBNB', 'WPOL', 'WAVAX', 'WCRO', 'WXDAI', 'CELO', 'WEMIX'].includes(pool.quote)) {
        existing.wrappedNativeQuoteSymbol = pool.quote;
      }
      if (typeof pool.quote === 'string' && ['USDC', 'USDT', 'DAI'].includes(pool.quote)) {
        existing.stableQuoteSymbol = pool.quote;
      }
      byFamily.set(familyKey, existing);
    }
  }

  return Array.from(byFamily.values()).sort((a, b) => a.familyKey.localeCompare(b.familyKey));
}

function buildGasRuntimePairsFromDeploymentStatus(data: DeploymentStatusFile): GruTransportPair[] {
  const familiesByKey = new Map(buildGasAssetFamiliesFromDeploymentStatus(data).map((family) => [family.familyKey, family]));
  const pairs: GruTransportPair[] = [];

  for (const [chainIdText, chain] of Object.entries(data.chains ?? {})) {
    const destinationChainId = Number(chainIdText);
    const seen = new Set<string>();
    for (const pool of chain.gasPmmPools ?? []) {
      const familyKey = typeof pool.familyKey === 'string' ? pool.familyKey : '';
      const mirroredSymbol = typeof pool.base === 'string' ? pool.base : '';
      if (!familyKey || !mirroredSymbol || seen.has(familyKey)) continue;
      seen.add(familyKey);
      const family = familiesByKey.get(familyKey);
      const canonicalSymbol = family?.canonicalSymbol138 ?? gasFamilyDefaults(familyKey, mirroredSymbol).canonicalSymbol138;
      pairs.push({
        key: `138-${destinationChainId}-${canonicalSymbol}-${mirroredSymbol}`,
        canonicalChainId: 138,
        destinationChainId,
        destinationChainName: chain.name ?? `Chain ${chainIdText}`,
        active: true,
        status: 'deployment_status_fallback',
        canonicalSymbol,
        mirroredSymbol,
        mappingKey: `${canonicalSymbol}:${destinationChainId}`,
        peerKey: `chain-${destinationChainId}`,
        assetClass: 'gas_native',
        familyKey,
        laneGroup: family?.laneGroup,
        backingMode: family?.backingMode,
        redeemPolicy: family?.redeemPolicy,
        wrappedNativeQuoteSymbol: family?.wrappedNativeQuoteSymbol,
        stableQuoteSymbol: family?.stableQuoteSymbol,
        mirrorDeploymentAddress: chain.gasMirrors?.[mirroredSymbol],
        mirrorDeployed: !!chain.gasMirrors?.[mirroredSymbol],
        canonicalEnabled: true,
        destinationEnabled: true,
        bridgeAvailable: chain.bridgeAvailable === true,
        bridgePeerConfigured: chain.bridgeAvailable === true,
        runtimeBridgeReady: chain.bridgeAvailable === true,
        runtimeReady: chain.bridgeAvailable === true && !!chain.gasMirrors?.[mirroredSymbol],
        eligible: true,
        runtimeMissingRequirements: chain.bridgeAvailable === true ? [] : ['bridgeAvailable is not true in deployment-status'],
        eligibilityBlockers: [],
      });
    }
  }

  return pairs.sort((a, b) => a.destinationChainId - b.destinationChainId || a.familyKey!.localeCompare(b.familyKey!));
}

function buildCanonicalCwFallback(chainIdFilter?: number | null): CwRegistryChain[] {
  const grouped = new Map<number, CwRegistryChain>();

  for (const spec of CANONICAL_TOKENS) {
    if (spec.type !== 'w') continue;
    for (const [chainIdText, address] of Object.entries(spec.addresses)) {
      const chainId = Number(chainIdText);
      if (!address || Number.isNaN(chainId)) continue;
      if (chainIdFilter && chainId !== chainIdFilter) continue;

      const existing = grouped.get(chainId) ?? {
        chainId,
        chainIdText,
        name: `Chain ${chainIdText}`,
        tokens: [],
      };

      existing.tokens.push({ symbol: spec.symbol, address });
      grouped.set(chainId, existing);
    }
  }

  return Array.from(grouped.values())
    .map((row) => ({
      ...row,
      tokens: row.tokens.sort((a, b) => a.symbol.localeCompare(b.symbol)),
    }))
    .sort((a, b) => a.chainId - b.chainId);
}

/** GET /report/assets/* — packaged report assets such as controlled token logos. */
router.get(/^\/assets\/(.+)$/, (req: Request, res: Response) => {
  const assetPath = String(req.params[0] ?? '');
  const publicRoot = path.resolve(__dirname, '../../../public');
  const resolved = path.resolve(publicRoot, assetPath);

  if (!resolved.startsWith(publicRoot) || !existsSync(resolved)) {
    res.status(404).json({ error: 'Asset not found' });
    return;
  }

  res.set('Cache-Control', 'public, max-age=86400, immutable');
  res.sendFile(resolved);
});

/** GET /report/logo/:symbol — extensionless public logo route for proxies that block static file extensions. */
router.get('/logo/:symbol', (req: Request, res: Response) => {
  const rawSymbol = String(req.params.symbol ?? '').trim();
  const publicRoot = path.resolve(__dirname, '../../../public/token-logos');
  const gruSymbol = rawSymbol.replace(/^cW(?=USD|EUR|GBP|AUD|JPY|CHF|CAD|XAU)/, 'c');
  const candidates = [
    rawSymbol === 'cWBTC' ? path.join(publicRoot, 'trustwallet/btc-logo.png') : '',
    rawSymbol.startsWith('ipfs-') ? path.join(publicRoot, 'ipfs', rawSymbol.replace(/^ipfs-/, '')) : '',
    path.join(publicRoot, 'gru', `${gruSymbol}.svg`),
  ].filter(Boolean);

  const resolved = candidates.find((candidate) => existsSync(candidate));
  if (!resolved) {
    res.status(404).json({ error: 'Logo not found' });
    return;
  }

  res.set('Cache-Control', 'public, max-age=86400, immutable');
  res.sendFile(resolved);
});

/** GET /report/cross-chain — cross-chain pools, bridge volume, atomic swaps (Chain 138, ALL Mainnet) */
router.get(
  '/cross-chain',
  cacheMiddleware(2 * 60 * 1000),
  async (req: Request, res: Response) => {
    try {
      const chainId = parseInt(req.query.chainId as string, 10) || 138;
      const report = await buildCrossChainReport(chainId);
      res.json({
        ...report,
        format: 'cross-chain-report',
        documentation: 'Use for CMC/CoinGecko submission alongside single-chain reports. Includes CCIP, Alltra, Trustless bridge events and volume by lane.',
      });
    } catch (error) {
      logger.error('Error building report/cross-chain:', error);
      res.status(500).json({
        error: 'Internal server error',
        crossChainPools: [],
        volumeByLane: [],
        atomicSwapVolume24h: 0,
        bridgeVolume24hTotal: 0,
        events: [],
      });
    }
  }
);

/** GET /report/all — all tokens, pools, liquidity, volume (unified) + cross-chain */
router.get(
  '/all',
  cacheMiddleware(2 * 60 * 1000),
  async (req: Request, res: Response) => {
    try {
      const chainIdParam = req.query.chainId as string | undefined;
      const chainIds = chainIdParam
        ? [parseInt(chainIdParam, 10)].filter((n) => !isNaN(n))
        : getSupportedChainIds();

      const tokensByChain: Record<number, Awaited<ReturnType<typeof buildTokenReport>>> = {};
      const poolsByChain: Record<number, Awaited<ReturnType<typeof poolRepo.getPoolsByChain>>> = {};

      for (const chainId of chainIds) {
        tokensByChain[chainId] = await buildTokenReport(chainId);
        poolsByChain[chainId] = filterPoolsForExposure(chainId, await poolRepo.getPoolsByChain(chainId));
      }

      const crossChainReport = await buildCrossChainReport(138).catch(() => null);
      const gruTransport = buildGruTransportOverview();

      const totalLiquidityByChain: Record<number, number> = {};
      const totalVolume24hByChain: Record<number, number> = {};
      for (const chainId of chainIds) {
        const pools = poolsByChain[chainId] || [];
        totalLiquidityByChain[chainId] = pools.reduce((s, p) => s + (p.totalLiquidityUsd || 0), 0);
        totalVolume24hByChain[chainId] = pools.reduce((s, p) => s + (p.volume24h || 0), 0);
      }

      res.json({
        generatedAt: new Date().toISOString(),
        chains: chainIds,
        tokens: tokensByChain,
        pools: poolsByChain,
        summary: {
          totalLiquidityUsdByChain: totalLiquidityByChain,
          totalVolume24hUsdByChain: totalVolume24hByChain,
          tokenCountByChain: Object.fromEntries(
            chainIds.map((c) => [c, (tokensByChain[c] || []).length])
          ),
          poolCountByChain: Object.fromEntries(
            chainIds.map((c) => [c, (poolsByChain[c] || []).length])
          ),
          crossChainBridgeVolume24h: crossChainReport?.bridgeVolume24hTotal,
          crossChainAtomicSwapVolume24h: crossChainReport?.atomicSwapVolume24h,
        },
        crossChain: crossChainReport
          ? {
              crossChainPools: crossChainReport.crossChainPools,
              volumeByLane: crossChainReport.volumeByLane,
              atomicSwapVolume24h: crossChainReport.atomicSwapVolume24h,
              bridgeVolume24hTotal: crossChainReport.bridgeVolume24hTotal,
            }
          : undefined,
        gruTransport,
      });
    } catch (error) {
      logger.error('Error building report/all:', error);
      res.status(500).json({ error: 'Internal server error' });
    }
  }
);

/** GET /report/coingecko — format suitable for CoinGecko submission / API */
router.get(
  '/coingecko',
  cacheMiddleware(2 * 60 * 1000),
  async (req: Request, res: Response) => {
    try {
      const chainId = parseInt(req.query.chainId as string, 10) || 138;
      const tokens = await buildTokenReport(chainId);

      const coingeckoFormat = tokens.map((t) => {
        const poolTvlSum = t.pools.reduce((sum, p) => sum + (Number.isFinite(p.tvl) ? p.tvl : 0), 0);
        return {
        chain_id: chainId,
        contract_address: t.address,
        id: `${t.symbol.toLowerCase()}-${chainId}`,
        symbol: t.symbol,
        name: t.name,
        asset_platform_id: chainId === 138 ? 'defi-oracle-meta' : chainId === 651940 ? 'all-mainnet' : `chain-${chainId}`,
        decimals: t.decimals,
        logo_uri: t.logoURI,
        original_logo_uri: t.originalLogoURI,
        description: describeToken(t),
        total_supply: t.totalSupply ? Number(t.totalSupply) : undefined,
        total_supply_raw: t.totalSupplyRaw,
        circulating_supply: t.circulatingSupply ? Number(t.circulatingSupply) : undefined,
        circulating_supply_formula: t.circulatingSupplyFormula,
        supply_proof_provenance: t.supplyProofProvenance,
        tracker_caveats: t.trackerCaveats,
        market_data: t.market
          ? {
              current_price: { usd: t.market.priceUsd },
              total_volume: t.market.volume24h,
              market_cap: t.market.marketCapUsd,
              liquidity_usd: Math.max(t.market.liquidityUsd ?? 0, poolTvlSum),
              last_updated: t.market.lastUpdated,
            }
          : undefined,
        liquidity_pools: t.pools.map((p) => ({
          pool_address: p.poolAddress,
          dex_id: p.dex,
          tvl_usd: p.tvl,
          volume_24h_usd: p.volume24h,
          source: p.source,
          status: p.status,
          status_reason: p.statusReason,
          role: p.role,
          section: p.section,
          public_routing_enabled: p.publicRoutingEnabled,
          base_symbol: p.token0Symbol,
          quote_symbol: p.token1Symbol,
        })),
      };
      });

      const crossChainReport = await buildCrossChainReport(chainId).catch(() => null);

      res.json({
        generatedAt: new Date().toISOString(),
        chainId,
        format: 'coingecko-submission',
        tokens: coingeckoFormat,
        crossChain: crossChainReport
          ? {
              crossChainPools: crossChainReport.crossChainPools,
              volumeByLane: crossChainReport.volumeByLane,
              atomicSwapVolume24h: crossChainReport.atomicSwapVolume24h,
              bridgeVolume24hTotal: crossChainReport.bridgeVolume24hTotal,
            }
          : undefined,
        documentation: 'https://www.coingecko.com/en/api/documentation',
      });
    } catch (error) {
      logger.error('Error building report/coingecko:', error);
      res.status(500).json({ error: 'Internal server error' });
    }
  }
);

/** GET /report/cmc — format suitable for CoinMarketCap submission / API */
router.get(
  '/cmc',
  cacheMiddleware(2 * 60 * 1000),
  async (req: Request, res: Response) => {
    try {
      const chainId = parseInt(req.query.chainId as string, 10) || 138;
      const tokens = await buildTokenReport(chainId);

      const cmcFormat = tokens.map((t) => ({
        chain_id: chainId,
        contract_address: t.address,
        symbol: t.symbol,
        name: t.name,
        decimals: t.decimals,
        logo_url: t.logoURI,
        original_logo_url: t.originalLogoURI,
        total_supply: t.totalSupply ? Number(t.totalSupply) : undefined,
        total_supply_raw: t.totalSupplyRaw,
        circulating_supply: t.circulatingSupply ? Number(t.circulatingSupply) : undefined,
        circulating_supply_formula: t.circulatingSupplyFormula,
        supply_proof_provenance: t.supplyProofProvenance,
        tracker_caveats: t.trackerCaveats,
        volume_24h: t.market?.volume24h,
        market_cap: t.market?.marketCapUsd,
        liquidity_usd: t.market?.liquidityUsd ?? t.pools.reduce((s, p) => s + p.tvl, 0),
        pairs: t.pools.map((p) => ({
          pair_address: p.poolAddress,
          dex_id: p.dex,
          base: t.address,
          quote: p.token0 === t.address ? p.token1 : p.token0,
          liquidity_usd: p.tvl,
          volume_24h_usd: p.volume24h,
          source: p.source,
          status: p.status,
          status_reason: p.statusReason,
          role: p.role,
          section: p.section,
          public_routing_enabled: p.publicRoutingEnabled,
        })),
      }));

      const crossChainReport = await buildCrossChainReport(chainId).catch(() => null);

      res.json({
        generatedAt: new Date().toISOString(),
        chainId,
        format: 'coinmarketcap-dex',
        tokens: cmcFormat,
        crossChain: crossChainReport
          ? {
              crossChainPools: crossChainReport.crossChainPools,
              volumeByLane: crossChainReport.volumeByLane,
              atomicSwapVolume24h: crossChainReport.atomicSwapVolume24h,
              bridgeVolume24hTotal: crossChainReport.bridgeVolume24hTotal,
            }
          : undefined,
        documentation: 'https://coinmarketcap.com/api/documentation',
      });
    } catch (error) {
      logger.error('Error building report/cmc:', error);
      res.status(500).json({ error: 'Internal server error' });
    }
  }
);

/** GET /report/external-indexer-readiness — operator-facing readiness for third-party trackers. */
router.get(
  '/external-indexer-readiness',
  cacheMiddleware(2 * 60 * 1000),
  async (req: Request, res: Response) => {
    try {
      const chainId = parseInt(req.query.chainId as string, 10) || 138;
      const tokens = await buildTokenReport(chainId);
      const pools = filterPoolsForExposure(chainId, await poolRepo.getPoolsByChain(chainId));
      const tokenPoolRows = tokens.flatMap((token) => token.pools);
      const positiveTokenPoolRows = tokenPoolRows.filter((pool) => pool.tvl > 0);
      const positiveIndexedPools = pools.filter((pool) => (pool.totalLiquidityUsd ?? 0) > 0);
      const totalLiquidityUsd = pools.reduce((sum, pool) => sum + (pool.totalLiquidityUsd || 0), 0);
      const totalTokenPoolLiquidityUsd = tokenPoolRows.reduce((sum, pool) => sum + (pool.tvl || 0), 0);
      const totalReportableLiquidityUsd = totalLiquidityUsd > 0 ? totalLiquidityUsd : totalTokenPoolLiquidityUsd;
      const gruPools = getGruV2DeploymentPoolRows().filter((pool) => pool.chainId === chainId);
      const gruRoutingEnabledPools = gruPools.filter((pool) => pool.status === 'routing_enabled' || pool.status === 'live');
      const publicBase = resolvePublicBaseUrl(req);

      res.set('Cache-Control', 'public, max-age=0, must-revalidate');
      res.json({
        generatedAt: new Date().toISOString(),
        chainId,
        schema: 'dbis-external-indexer-readiness/v1',
        summary: {
          tokenCount: tokens.length,
          indexedPoolCount: pools.length,
          positiveIndexedPoolCount: positiveIndexedPools.length,
          tokenPoolRows: tokenPoolRows.length,
          positiveTokenPoolRows: positiveTokenPoolRows.length,
          totalLiquidityUsd: totalReportableLiquidityUsd,
          gruV2PoolCount: gruPools.length,
          gruV2RoutingEnabledPoolCount: gruRoutingEnabledPools.length,
        },
        endpoints: {
          all: `${publicBase}/api/v1/report/all?chainId=${chainId}`,
          coingecko: `${publicBase}/api/v1/report/coingecko?chainId=${chainId}`,
          cmc: `${publicBase}/api/v1/report/cmc?chainId=${chainId}`,
          tokenList: `${publicBase}/api/v1/report/token-list?chainId=${chainId}`,
          gruV2PmmPools: `${publicBase}/api/v1/report/gru-v2-pmm-pools?chainId=${chainId}`,
          adoptionReadiness: `${publicBase}/api/v1/report/adoption-readiness`,
        },
        trackers: {
          defiLlama: {
            status: chainId === 138 ? 'merged_chain_listed_tvl_pending_server_pricing' : 'not_applicable',
            readyFromDbisSide: chainId === 138 && totalReportableLiquidityUsd > 0,
            blocker:
              chainId === 138
                ? 'Chain listed at defillama.com/chain/defi-oracle-meta; TVL $0 until defillama-server prices cUSDT/cUSDC on dfio_meta_main.'
                : undefined,
            submission: chainId === 138 ? 'https://github.com/DefiLlama/DefiLlama-Adapters/pull/19198' : undefined,
            chainPage: chainId === 138 ? 'https://defillama.com/chain/defi-oracle-meta' : undefined,
            mergedAt: chainId === 138 ? '2026-05-21T22:13:42Z' : undefined,
          },
          coinGecko: {
            status: totalReportableLiquidityUsd > 0 && tokens.length > 0 ? 'report_ready_external_listing_pending' : 'needs_internal_data',
            readyFromDbisSide: totalReportableLiquidityUsd > 0 && tokens.length > 0,
            blocker: 'CoinGecko asset-platform and token listing acceptance is external to this report API.',
          },
          coinMarketCap: {
            status: totalReportableLiquidityUsd > 0 && positiveTokenPoolRows.length > 0 ? 'report_ready_external_listing_pending' : 'needs_internal_data',
            readyFromDbisSide: totalReportableLiquidityUsd > 0 && positiveTokenPoolRows.length > 0,
            blocker: 'CoinMarketCap DEX/listing acceptance is external to this report API.',
          },
          dexScreener: {
            status: chainId === 138 ? 'chain_indexing_external_pending' : 'report_ready_external_listing_pending',
            readyFromDbisSide: chainId === 138 && gruRoutingEnabledPools.length > 0,
            blocker: chainId === 138 ? 'Dexscreener must index Chain 138 and its native pairs before native pair pages appear.' : undefined,
          },
        },
      });
    } catch (error) {
      logger.error('Error building report/external-indexer-readiness:', error);
      res.status(500).json({ error: 'Internal server error' });
    }
  }
);

/** GET /report/metamask-price-feed — MetaMask / Consensys price-provider submission bundle for ISO-4217 c* tokens. */
router.get(
  '/metamask-price-feed',
  cacheMiddleware(2 * 60 * 1000),
  async (req: Request, res: Response) => {
    try {
      const chainId = parseInt(req.query.chainId as string, 10) || 138;
      const publicBase = resolvePublicBaseUrl(req);

      const tokens = getCanonicalTokensByChain(chainId)
        .map((spec) => {
          const address = spec.addresses[chainId];
          if (!address) return null;
          const priceUsd = getCanonicalPriceUsd(chainId, address);
          return {
            chainId,
            address,
            symbol: spec.symbol,
            name: spec.name,
            decimals: spec.decimals,
            priceUsd,
            extensions: buildIso4217TokenListExtensions(spec),
          };
        })
        .filter((row): row is NonNullable<typeof row> => Boolean(row));

      res.json({
        generatedAt: new Date().toISOString(),
        schema: 'dbis-metamask-price-feed/v1',
        chainId,
        chainName: 'DeFi Oracle Meta Mainnet',
        assetPlatformId: 'defi-oracle-meta',
        iso4217Pricing: true,
        fxLastRefreshAt: getIso4217FxLastRefreshAt() || null,
        canonicalPriceSnapshot: getCanonicalPriceSnapshotGeneratedAt(),
        metamaskPriceApiStatus: 'chain_138_not_registered_on_price_api_cx_metamask_io',
        spotPricesV2: `${publicBase}/token-aggregation/api/v1/prices/metamask/v2/chains/${chainId}/spot-prices?tokenAddresses={addresses}&vsCurrency=usd`,
        spotPricesV1: `${publicBase}/token-aggregation/api/v1/prices/metamask/v1/chains/${chainId}/spot-prices/{tokenAddress}?vsCurrency=usd`,
        coingeckoReport: `${publicBase}/token-aggregation/api/v1/report/coingecko?chainId=${chainId}`,
        tokenList: `${publicBase}/token-aggregation/api/v1/report/token-list?chainId=${chainId}`,
        tokens,
        submissionNotes: [
          'Request Consensys to register chainId 138 on price.api.cx.metamask.io pointing at spotPricesV2, or list tokens on CoinGecko under asset platform defi-oracle-meta.',
          'c* = Compliant eMoney; XXX = ISO-4217; C = Cash (M1); T = Treasury — coingeckoPriceProxyId is USD display proxy only.',
          'Live FX for ISO-4217 fiat codes refreshes every 5 minutes from Frankfurter + CoinGecko reference markets.',
        ],
      });
    } catch (error) {
      logger.error('Error building report/metamask-price-feed:', error);
      res.status(500).json({ error: 'Internal server error' });
    }
  },
);

/** GET /report/token-price/:symbol — compact reviewer-facing price and evidence snapshot. */
router.get(
  '/token-price/:symbol',
  cacheMiddleware(60 * 1000),
  async (req: Request, res: Response) => {
    try {
      const symbol = String(req.params.symbol || '').trim();
      const chainId = parseInt(req.query.chainId as string, 10) || 1;
      const tokens = await buildTokenReport(chainId);
      const token = tokens.find((entry) => entry.symbol.toLowerCase() === symbol.toLowerCase());

      if (!token) {
        res.status(404).json({
          error: 'Token not found',
          symbol,
          chainId,
        });
        return;
      }

      const poolLiquidityUsd = token.pools.reduce((sum, pool) => sum + (pool.tvl || 0), 0);
      const marketLiquidityUsd = token.market?.liquidityUsd ?? 0;
      const liquidityUsd = marketLiquidityUsd > 0 ? marketLiquidityUsd : poolLiquidityUsd;
      const priceUsd = token.market?.priceUsd;
      const circulatingSupply = token.circulatingSupply ? Number(token.circulatingSupply) : undefined;
      const totalSupply = token.totalSupply ? Number(token.totalSupply) : undefined;
      const marketCapUsd =
        token.market?.marketCapUsd ??
        (priceUsd !== undefined && circulatingSupply !== undefined ? priceUsd * circulatingSupply : undefined);

      res.json({
        generatedAt: new Date().toISOString(),
        schema: 'dbis-token-price-evidence/v1',
        chainId,
        token: {
          address: token.address,
          symbol: token.symbol,
          name: token.name,
          decimals: token.decimals,
          type: token.type,
          registryFamily: token.registryFamily,
          logoURI: token.logoURI,
        },
        price: {
          usd: priceUsd,
          source: token.market ? 'token-aggregation' : priceUsd !== undefined ? 'canonical-fallback' : 'unavailable',
          lastUpdated: token.market?.lastUpdated,
          caveat:
            chainId === 1 && token.symbol === 'cWUSDC'
              ? 'This is DBIS tracker-submission evidence. Etherscan USD Value appears only after Etherscan/CoinGecko/Dex indexers accept a public price source.'
              : undefined,
        },
        supply: {
          totalSupply,
          totalSupplyRaw: token.totalSupplyRaw,
          circulatingSupply,
          circulatingSupplyFormula: token.circulatingSupplyFormula,
          proof: token.supplyProofProvenance,
          caveats: token.trackerCaveats ?? [],
        },
        valuation: {
          marketCapUsd,
          liquidityUsd,
          volume24hUsd: token.market?.volume24h ?? 0,
        },
        pools: token.pools.map((pool) => ({
          poolAddress: pool.poolAddress,
          dexId: pool.dex,
          tvlUsd: pool.tvl,
          volume24hUsd: pool.volume24h,
          source: pool.source,
          status: pool.status,
          statusReason: pool.statusReason,
          role: pool.role,
          publicRoutingEnabled: pool.publicRoutingEnabled,
          token0: {
            address: pool.token0,
            symbol: pool.token0Symbol,
          },
          token1: {
            address: pool.token1,
            symbol: pool.token1Symbol,
          },
        })),
        submissionLinks: {
          coingeckoReport: `${resolvePublicBaseUrl(req)}/api/v1/report/coingecko?chainId=${chainId}`,
          cmcReport: `${resolvePublicBaseUrl(req)}/api/v1/report/cmc?chainId=${chainId}`,
          tokenList: `${resolvePublicBaseUrl(req)}/api/v1/report/token-list?chainId=${chainId}`,
          etherscan:
            chainId === 1
              ? `https://etherscan.io/token/${token.address}`
              : undefined,
        },
      });
    } catch (error) {
      logger.error('Error building report/token-price:', error);
      res.status(500).json({ error: 'Internal server error' });
    }
  }
);

/** GET /report/token-list/static/ethereum-mainnet — pinned Uniswap-schema list for tokenlists.org submissions. */
router.get(
  '/token-list/static/ethereum-mainnet',
  cacheMiddleware(5 * 60 * 1000),
  (req: Request, res: Response) => {
    try {
      const payload = loadStaticEthereumMainnetTokenList();
      if (!payload) {
        return res.status(404).json({ error: 'Static ethereum-mainnet token list not found' });
      }
      return finalizeUniswapTokenListResponse(req, res, payload, [1]);
    } catch (error) {
      logger.error('Error serving static ethereum-mainnet token list:', error);
      res.status(500).json({ error: 'Internal server error' });
    }
  }
);

/** GET /report/token-list — Uniswap token list schema (version object, checksummed addresses, extensions bag).
 * If TOKEN_LIST_JSON_URL is set (e.g. GitHub raw URL), fetches and returns that JSON; optional ?chainId= filters tokens.
 */
router.get(
  '/token-list',
  cacheMiddleware(5 * 60 * 1000),
  async (req: Request, res: Response) => {
    try {
      const chainIdParam = req.query.chainId as string | undefined;
      const walletEligibleOnly =
        String(req.query.wallet ?? req.query.walletEligible ?? '').trim() === '1' ||
        String(req.query.wallet ?? req.query.walletEligible ?? '').trim().toLowerCase() === 'true';
      const chainIds = chainIdParam
        ? [parseInt(chainIdParam, 10)].filter((n) => !isNaN(n))
        : getSupportedChainIds();

      const finalizeOptions = { walletEligibleOnly };

      if (chainIds.length === 1 && chainIds[0] === 138) {
        const fileList = loadDbis138TokenListFromFile();
        if (fileList) {
          return finalizeUniswapTokenListResponse(req, res, fileList, chainIds, finalizeOptions);
        }
      }

      const tokenListUrl = process.env.TOKEN_LIST_JSON_URL?.trim();
      if (tokenListUrl) {
        try {
          const data = (await fetchRemoteJson(tokenListUrl)) as Record<string, unknown>;
          let tokens = Array.isArray(data.tokens) ? data.tokens : [];
          if (chainIds.length === 1) {
            tokens = tokens.filter((token) => {
              const record = token as { chainId?: number };
              return record.chainId === chainIds[0];
            });
          }
          return finalizeUniswapTokenListResponse(
            req,
            res,
            {
              ...data,
              tokens,
            },
            chainIds,
            finalizeOptions,
          );
        } catch (err) {
          logger.error('TOKEN_LIST_JSON_URL fetch failed, using built-in token list:', err);
        }
      }

      const list: Array<Record<string, unknown>> = [];

      for (const chainId of chainIds) {
        const specs = getCanonicalTokensByChain(chainId);
        for (const spec of specs) {
          const address = spec.addresses[chainId];
          if (!address) continue;
          if (walletEligibleOnly && !isWalletWatchAssetEligible(spec, chainId)) continue;
          const originalLogoURI = getLogoUriForSpec(spec);
          list.push({
            chainId,
            address,
            symbol: spec.symbol,
            name: spec.name,
            decimals: spec.decimals,
            type: spec.type,
            logoURI: absoluteLogoUri(req, originalLogoURI, spec.symbol),
            originalLogoURI,
            registryFamily: getTokenRegistryFamily(spec),
            familySymbol: spec.familySymbol,
            deploymentVersion: spec.deploymentVersion,
            deploymentStatus: spec.deploymentStatus,
            preferredForX402: spec.preferredForX402,
            extensions: buildIso4217TokenListExtensions(spec),
          });
        }
      }

      return finalizeUniswapTokenListResponse(
        req,
        res,
        {
          name: 'GRU Canonical Token List',
          version: { major: 1, minor: 0, patch: 0 },
          timestamp: new Date().toISOString(),
          logoURI: 'https://d-bis.org/brand/chain-138.svg',
          tokens: list,
        },
        chainIds,
        finalizeOptions,
      );
    } catch (error) {
      logger.error('Error building report/token-list:', error);
      res.status(500).json({ error: 'Internal server error' });
    }
  }
);

/** GET /report/cw-registry — live cW* registry from deployment-status.json when available. */
router.get('/cw-registry', async (req: Request, res: Response) => {
  try {
    const chainIdParam = req.query.chainId as string | undefined;
    const chainIdFilter = chainIdParam ? parseInt(chainIdParam, 10) : null;
    const fileBackedRegistry = loadDeploymentStatusFile();

    let chains = fileBackedRegistry
      ? buildCwRegistryChains(fileBackedRegistry.data)
      : buildCanonicalCwFallback(chainIdFilter);

    if (chainIdFilter && !Number.isNaN(chainIdFilter)) {
      chains = chains.filter((row) => row.chainId === chainIdFilter);
    }

    res.set('Cache-Control', 'public, max-age=0, must-revalidate');
    res.json({
      generatedAt: new Date().toISOString(),
      source: fileBackedRegistry ? 'deployment-status-file' : 'canonical-fallback',
      complete: !!fileBackedRegistry,
      version: fileBackedRegistry?.data.version,
      updated: fileBackedRegistry?.data.updated,
      lastModified: fileBackedRegistry?.lastModified,
      chains,
    });
  } catch (error) {
    logger.error('Error building report/cw-registry:', error);
    res.status(500).json({ error: 'Internal server error', chains: [] });
  }
});

/** GET /report/gru-v2-pmm-pools — all GRU v2 PMM pools from deployment-status (stable, volatile, gas) with resolved token addresses. */
router.get('/gru-v2-pmm-pools', async (req: Request, res: Response) => {
  try {
    const chainIdParam = req.query.chainId as string | undefined;
    const chainIdFilter = chainIdParam ? parseInt(chainIdParam, 10) : null;
    const fileBacked = loadDeploymentStatusFile();
    let pools = getGruV2DeploymentPoolRows();

    if (chainIdFilter && !Number.isNaN(chainIdFilter)) {
      pools = pools.filter((p) => p.chainId === chainIdFilter);
    }

    res.set('Cache-Control', 'public, max-age=0, must-revalidate');
    res.json({
      generatedAt: new Date().toISOString(),
      source: fileBacked ? 'deployment-status-file' : 'none',
      complete: !!fileBacked,
      version: fileBacked?.data.version,
      updated: fileBacked?.data.updated,
      lastModified: fileBacked?.lastModified,
      homeChainId: fileBacked?.data.homeChainId,
      count: pools.length,
      lifecycle: {
        live: pools.filter((pool) => pool.status === 'live').length,
        routingEnabled: pools.filter((pool) => pool.status === 'routing_enabled').length,
        configured: pools.filter((pool) => pool.status === 'configured').length,
        proofRequired: pools.filter((pool) => pool.status === 'proof_required').length,
        routeVisible: pools.filter((pool) => pool.status === 'live' || pool.status === 'routing_enabled').length,
      },
      pools,
    });
  } catch (error) {
    logger.error('Error building report/gru-v2-pmm-pools:', error);
    res.status(500).json({ error: 'Internal server error', pools: [] });
  }
});

/** GET /report/adoption-readiness — summary gates for institutional and tracker/listing readiness. */
router.get('/adoption-readiness', async (_req: Request, res: Response) => {
  try {
    const chainIds = getSupportedChainIds();
    const tokensByChain: Record<number, Awaited<ReturnType<typeof buildTokenReport>>> = {};
    for (const chainId of chainIds) {
      tokensByChain[chainId] = await buildTokenReport(chainId);
    }

    const allTokens = Object.values(tokensByChain).flat();
    const candidates = allTokens.filter((token) =>
      isGruSupplyTrackedCandidate(token.symbol, token.type, token.registryFamily)
    );
    const nonReportablePlaceholder = candidates.filter(
      (token) => token.supplyProofProvenance?.source === 'deterministic-placeholder-address'
    );
    const reportableCandidates = candidates.filter(
      (token) => token.supplyProofProvenance?.source !== 'deterministic-placeholder-address'
    );
    const proved = reportableCandidates.filter((token) => token.supplyProofProvenance && token.supplyProofProvenance.source !== 'missing-supply-proof');
    const proofRequired = reportableCandidates.filter((token) => token.supplyProofProvenance?.source === 'missing-supply-proof');
    const silent = reportableCandidates.filter((token) => !token.supplyProofProvenance);
    const externalOfficialQuoteLiquidity = reportableCandidates.filter(hasExternalOfficialQuoteLiquidity);
    const liquidityPositive = reportableCandidates.filter(
      (token) => (token.market?.liquidityUsd ?? 0) > 0 || token.pools.some((pool) => pool.tvl > 0) || hasExternalOfficialQuoteLiquidity(token)
    );
    const poolIndexed = reportableCandidates.filter((token) => token.pools.length > 0);
    const liquidityMissing = reportableCandidates.filter(
      (token) => (token.market?.liquidityUsd ?? 0) <= 0 && !token.pools.some((pool) => pool.tvl > 0) && !hasExternalOfficialQuoteLiquidity(token)
    );
    const liquidityMissingWithPools = liquidityMissing.filter((token) => token.pools.length > 0);
    const liquidityMissingWithoutPools = liquidityMissing.filter((token) => token.pools.length === 0);
    const gruPools = getGruV2DeploymentPoolRows();
    const groupTokensByChain = (tokens: typeof candidates) =>
      tokens
        .reduce<Array<{ chainId: number; count: number; symbols: string[] }>>((groups, token) => {
          let group = groups.find((row) => row.chainId === token.chainId);
          if (!group) {
            group = { chainId: token.chainId, count: 0, symbols: [] };
            groups.push(group);
          }
          group.count += 1;
          group.symbols.push(token.symbol);
          return groups;
        }, [])
        .map((group) => ({
          ...group,
          symbols: Array.from(new Set(group.symbols)).sort(),
        }))
        .sort((a, b) => a.chainId - b.chainId);

    res.set('Cache-Control', 'public, max-age=0, must-revalidate');
    res.json({
      generatedAt: new Date().toISOString(),
      scope: 'gru-c-and-cw-assets',
      counts: {
        candidates: candidates.length,
        reportableCandidates: reportableCandidates.length,
        nonReportablePlaceholder: nonReportablePlaceholder.length,
        proved: proved.length,
        proofRequired: proofRequired.length,
        silent: silent.length,
        poolIndexed: poolIndexed.length,
        liquidityPositive: liquidityPositive.length,
        liquidityMissing: liquidityMissing.length,
        liquidityMissingWithPools: liquidityMissingWithPools.length,
        liquidityMissingWithoutPools: liquidityMissingWithoutPools.length,
        externalOfficialQuoteLiquidity: externalOfficialQuoteLiquidity.length,
        gruV2Pools: gruPools.length,
        gruV2PoolsWithStatus: gruPools.filter((pool) => !!pool.status).length,
      },
      institutional: {
        score: Math.round(
          100 *
            ((silent.length === 0 ? 0.25 : 0) +
              (proved.length / Math.max(reportableCandidates.length, 1)) * 0.35 +
              (poolIndexed.length / Math.max(reportableCandidates.length, 1)) * 0.2 +
              (gruPools.length > 0 && gruPools.every((pool) => !!pool.status) ? 0.2 : 0))
        ),
        blockers: [
          proofRequired.length > 0 ? `${proofRequired.length} assets still require supply-proof artifacts.` : null,
          silent.length > 0 ? `${silent.length} assets have no proof state.` : null,
          gruPools.some((pool) => !pool.status) ? 'One or more GRU v2 pools lacks lifecycle status.' : null,
        ].filter(Boolean),
      },
      cryptoListing: {
        score: Math.round(
          100 *
            ((proved.length / Math.max(reportableCandidates.length, 1)) * 0.45 +
              (liquidityPositive.length / Math.max(reportableCandidates.length, 1)) * 0.35 +
              (poolIndexed.length / Math.max(reportableCandidates.length, 1)) * 0.2)
        ),
        blockers: [
          proofRequired.length > 0 ? 'Most c*/cW* assets are proof-gated for supply and market-cap claims.' : null,
          liquidityPositive.length < reportableCandidates.length ? 'Not every reportable c*/cW* asset has positive indexed liquidity in the report API.' : null,
        ].filter(Boolean),
      },
      blockerInventory: {
        proofRequiredByChain: groupTokensByChain(proofRequired),
        liquidityMissingByChain: groupTokensByChain(liquidityMissing),
        liquidityMissingWithPoolsByChain: groupTokensByChain(liquidityMissingWithPools),
        liquidityMissingWithoutPoolsByChain: groupTokensByChain(liquidityMissingWithoutPools),
        liquidityMissingDetails: liquidityMissing
          .map((token) => ({
            chainId: token.chainId,
            symbol: token.symbol,
            address: token.address,
            poolCount: token.pools.length,
            zeroTvlPoolCount: token.pools.filter((pool) => pool.tvl <= 0).length,
            marketLiquidityUsd: token.market?.liquidityUsd ?? 0,
            category: token.pools.length > 0 ? 'configured_or_indexed_pools_zero_tvl' : 'no_visible_pool_binding',
          }))
          .sort((a, b) => a.chainId - b.chainId || a.symbol.localeCompare(b.symbol)),
        externalOfficialQuoteLiquidityByChain: groupTokensByChain(externalOfficialQuoteLiquidity),
        nonReportablePlaceholderByChain: groupTokensByChain(nonReportablePlaceholder),
        gruV2PoolsMissingStatus: gruPools
          .filter((pool) => !pool.status)
          .map((pool) => ({
            chainId: pool.chainId,
            poolAddress: pool.poolAddress,
            baseSymbol: pool.baseSymbol,
            quoteSymbol: pool.quoteSymbol,
          })),
        notes: [
          'proof_required means the report intentionally withholds totalSupply, circulatingSupply, and marketCap claims for that asset.',
          'nonReportablePlaceholder means the configured address is intentionally visible for roadmap traceability but is not a deployed ERC-20 proof surface.',
          'liquidityMissing means no positive indexed liquidity is currently visible through the report API for that asset.',
          'External official quote mirrors (public-chain USDC/USDT and ALL AUSDC/AUSDT) are not GRU pool blockers when their canonical token binding is proved; their public venue liquidity is maintained by the issuer/external market and should not be confused with repo-native cW*/Chain 138 liquidity.',
          'A configured pool or registry entry is not the same thing as tracker-grade supply proof or live positive liquidity.',
        ],
      },
      proofRequiredSample: proofRequired.slice(0, 20).map((token) => ({
        chainId: token.chainId,
        symbol: token.symbol,
        address: token.address,
        status: token.supplyProofProvenance?.status,
      })),
    });
  } catch (error) {
    logger.error('Error building report/adoption-readiness:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

/** GET /report/gas-registry — live gas-family rollout registry from deployment-status.json plus GRU transport metadata. */
router.get('/gas-registry', async (req: Request, res: Response) => {
  try {
    const chainIdParam = req.query.chainId as string | undefined;
    const chainIdFilter = chainIdParam ? parseInt(chainIdParam, 10) : null;
    const fileBackedRegistry = loadDeploymentStatusFile();
    const gruTransport = buildGruTransportOverview();
    const loaderRuntimePairs = getActiveTransportPairs();
    const fallbackRuntimePairs = fileBackedRegistry ? buildGasRuntimePairsFromDeploymentStatus(fileBackedRegistry.data) : [];
    const runtimeGasPairs = (loaderRuntimePairs.length > 0 ? loaderRuntimePairs : fallbackRuntimePairs)
      .filter((pair) => pair.assetClass === 'gas_native')
      .map((pair) => ({
        key: pair.key,
        destinationChainId: pair.destinationChainId,
        destinationChainName: pair.destinationChainName ?? null,
        familyKey: pair.familyKey ?? null,
        canonicalSymbol: pair.canonicalSymbol,
        mirroredSymbol: pair.mirroredSymbol,
        wrappedNativeQuoteSymbol: pair.wrappedNativeQuoteSymbol ?? null,
        stableQuoteSymbol: pair.stableQuoteSymbol ?? null,
        backingMode: pair.backingMode ?? null,
        redeemPolicy: pair.redeemPolicy ?? null,
        runtimeReady: pair.runtimeReady === true,
        supplyInvariantSatisfied: pair.supplyInvariantSatisfied ?? null,
        eligibilityBlockers: Array.isArray(pair.eligibilityBlockers) ? pair.eligibilityBlockers : [],
        runtimeMissingRequirements: Array.isArray(pair.runtimeMissingRequirements)
          ? pair.runtimeMissingRequirements
          : [],
      }));

    let chains = fileBackedRegistry ? buildGasRegistryChains(fileBackedRegistry.data) : [];
    if (chainIdFilter && !Number.isNaN(chainIdFilter)) {
      chains = chains.filter((row) => row.chainId === chainIdFilter);
    }

    res.set('Cache-Control', 'public, max-age=0, must-revalidate');
    res.json({
      generatedAt: new Date().toISOString(),
      source: fileBackedRegistry ? 'deployment-status-file' : 'transport-config-only',
      complete: !!fileBackedRegistry,
      version: fileBackedRegistry?.data.version,
      updated: fileBackedRegistry?.data.updated,
      lastModified: fileBackedRegistry?.lastModified,
      gasAssetFamilies: gruTransport?.gasAssetFamilies ?? [],
      gasRedeemGroups: gruTransport?.gasRedeemGroups ?? [],
      gasProtocolExposure: gruTransport?.gasProtocolExposure ?? [],
      runtimePairs: runtimeGasPairs,
      chains,
    });
  } catch (error) {
    logger.error('Error building report/gas-registry:', error);
    res.status(500).json({ error: 'Internal server error', chains: [] });
  }
});

/** GET /report/canonical — raw canonical spec list (no DB merge) */
router.get(
  '/canonical',
  cacheMiddleware(10 * 60 * 1000),
  async (req: Request, res: Response) => {
    try {
      const gruTransport = buildGruTransportOverview();
      res.json({
        generatedAt: new Date().toISOString(),
        gruTransport,
        tokens: CANONICAL_TOKENS.map((t) => ({
          symbol: t.symbol,
          name: t.name,
          type: t.type,
          decimals: t.decimals,
          currencyCode: t.currencyCode,
          registryFamily: getTokenRegistryFamily(t),
          familySymbol: t.familySymbol,
          deploymentVersion: t.deploymentVersion,
          deploymentStatus: t.deploymentStatus,
          preferredForX402: t.preferredForX402,
          liquiditySourceSymbol: t.liquiditySourceSymbol,
          addresses: t.addresses,
        })),
      });
    } catch (error) {
      logger.error('Error building report/canonical:', error);
      res.status(500).json({ error: 'Internal server error' });
    }
  }
);

/** GET /report/pool-registry — curated DODO PMM + UniV2 pools across supported chains. */
router.get('/pool-registry', cacheMiddleware(60 * 1000), async (req: Request, res: Response) => {
  try {
    const chainIdParam = req.query.chainId as string | undefined;
    const chainIdFilter = chainIdParam ? parseInt(chainIdParam, 10) : null;
    const baseReport = buildCuratedPoolRegistry(chainIdFilter && !Number.isNaN(chainIdFilter) ? chainIdFilter : null);
    const report = await enrichCuratedPoolRegistryWithLiveLiquidity(baseReport);
    res.set('Cache-Control', 'public, max-age=0, must-revalidate');
    res.json(report);
  } catch (error) {
    logger.error('Error building report/pool-registry:', error);
    res.status(500).json({ error: 'Internal server error', pools: [] });
  }
});

/** GET /report/lp-positions — on-chain LP share scan for DODO DVM + UniV2 pair tokens. */
router.get('/lp-positions', cacheMiddleware(30 * 1000), async (req: Request, res: Response) => {
  try {
    const chainId = parseInt(String(req.query.chainId ?? '138'), 10);
    const address = String(req.query.address ?? '').trim();
    const hintsRaw = String(req.query.hintAddresses ?? '').trim();
    const hintTokenAddresses = hintsRaw
      ? hintsRaw.split(',').map((item) => item.trim()).filter(Boolean)
      : [];

    if (!chainId || !address) {
      res.status(400).json({ error: 'chainId and address are required' });
      return;
    }

    const report = await buildLpPositionsReport({ chainId, address, hintTokenAddresses });
    res.set('Cache-Control', 'public, max-age=0, must-revalidate');
    res.json(report);
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Internal server error';
    if (message === 'Invalid address') {
      res.status(400).json({ error: message });
      return;
    }
    logger.error('Error building report/lp-positions:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

export default router;
