/**
 * Canonical token list for GRU base money, W-tokens, asset (ac*), and debt (vdc* / sdc*) tokens.
 * Used for CMC/CoinGecko reporting and token-aggregation indexing.
 * Addresses can be overridden via env (e.g. CUSDC_ADDRESS_138) or filled by indexer.
 */

import { isISO4217Supported } from './iso4217-symbol-registry';
import { isMonetaryUnitSupported } from './monetary-unit-symbol-registry';
import { loadTokenMappingLoader } from './repo-config-loader';

export type TokenType = 'base' | 'w' | 'asset' | 'debt';
export type TokenRegistryFamily = 'iso4217' | 'commodity' | 'monetary_unit' | 'gas_native' | 'unclassified';

export interface CanonicalTokenSpec {
  symbol: string;
  name: string;
  type: TokenType;
  decimals: number;
  currencyCode?: string;
  registryFamily?: TokenRegistryFamily;
  /** ChainId -> contract address (placeholder or from env) */
  addresses: Partial<Record<number, string>>;
  description?: string;
  websiteUrl?: string;
  logoUrl?: string;
  /** v1 matrix symbol for origin reference only (e.g. cXUSDC when bridged); on Chain 138 symbol is v0 only (no X) */
  v1Symbol?: string;
  /** v0 symbol alias; on ChainID 138 tokens use v0 only (cUSDC, cUSDT), no chain designator */
  v0Alias?: string;
  /** Shared family symbol when multiple on-chain deployments exist for the same monetary unit. */
  familySymbol?: string;
  /** Deployment version when a family has multiple contract surfaces. */
  deploymentVersion?: string;
  /** Deployment lifecycle status (for example active or staged). */
  deploymentStatus?: string;
  /** Whether this deployment is the preferred x402 / permit-capable surface. */
  preferredForX402?: boolean;
  /** Symbol whose current liquidity should be used for quote fallback until cutover. */
  liquiditySourceSymbol?: string;
}

interface GruTransportDeployment {
  version?: string;
  address?: string;
  status?: string;
}

interface GruTransportCanonicalToken {
  symbol?: string;
  activeVersion?: string;
  activeAddress?: string;
  x402PreferredVersion?: string;
  x402PreferredAddress?: string;
  deployments?: GruTransportDeployment[];
}

const CHAIN_138 = 138;
const CHAIN_25 = 25; // Cronos
const CHAIN_651940 = 651940;
const LEGACY_CHAIN_ENV_SUFFIX: Partial<Record<number, string>> = {
  1: 'MAINNET',
  10: 'OPTIMISM',
  25: 'CRONOS',
  56: 'BSC',
  100: 'GNOSIS',
  137: 'POLYGON',
  42161: 'ARBITRUM',
  43114: 'AVALANCHE',
  8453: 'BASE',
};
/** L2/mainnet chain IDs for cUSDT/cUSDC multichain (env: CUSDT_ADDRESS_56, CUSDC_ADDRESS_137, etc.) */
const L2_CHAIN_IDS = [1, 56, 137, 10, 42161, 8453, 43114, 25, 100, 42220, 1111] as const;
const GRU_CW_CHAIN_IDS = [1, 56, 137, 10, 42161, 8453, 43114, 100, 42220] as const;
const BTC_CW_CHAIN_IDS = [1, 10, 25, 56, 100, 137, 42161, 42220, 43114, 8453, 1111] as const;
const ETH_MAINNET_CW_CHAIN_IDS = [1] as const;
const ETH_L2_CW_CHAIN_IDS = [10, 42161, 8453] as const;
const BNB_CW_CHAIN_IDS = [56] as const;
const POL_CW_CHAIN_IDS = [137] as const;
const AVAX_CW_CHAIN_IDS = [43114] as const;
const CRO_CW_CHAIN_IDS = [25] as const;
const XDAI_CW_CHAIN_IDS = [100] as const;
const CELO_CW_CHAIN_IDS = [42220] as const;
const WEMIX_CW_CHAIN_IDS = [1111] as const;
/** Verified addresses from CHAIN138_TOKEN_ADDRESSES, .env, and deployment summaries */
const FALLBACK_ADDRESSES: Record<string, Partial<Record<number, string>>> = {
  USDC: {
    [CHAIN_138]: '0x71D6687F38b93CCad569Fa6352c876eea967201b',
  },
  USDT: {
    [CHAIN_138]: '0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1',
  },
  cUSDC: {
    [CHAIN_138]: '0xf22258f57794CC8E06237084b353Ab30fFfa640b',
    [CHAIN_651940]: '0xa95EeD79f84E6A0151eaEb9d441F9Ffd50e8e881', // AUSDC on ALL Mainnet
    [1]: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Ethereum USDC
    [56]: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', // BSC USDC
    [137]: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', // Polygon USDC
    [100]: '0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83', // Gnosis USDC
    [10]: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', // Optimism USDC
    [42161]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // Arbitrum USDC
    [8453]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // Base USDC
    [43114]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E', // Avalanche USDC
    [CHAIN_25]: '0xc21223249CA28397B4B6541dfFaEcC539BfF0c59', // Cronos USDC
    [42220]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C', // Celo USDC
    [1111]: '0xE3F5a90F9cb311505cd691a46596599aA1A0AD7D', // Wemix USDC
  },
  cUSDT: {
    [CHAIN_138]: '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22',
    [CHAIN_651940]: '0x015B1897Ed5279930bC2Be46F661894d219292A6', // AUSDT primary on ALL Mainnet
    [1]: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // Ethereum USDT
    [56]: '0x55d398326f99059fF775485246999027B3197955', // BSC USDT
    [137]: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', // Polygon USDT
    [100]: '0x4ECaBa5870353805a9F068101A40E0f32ed605C6', // Gnosis USDT
    [10]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', // Optimism USDT
    [42161]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', // Arbitrum USDT
    [8453]: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2', // Base USDT
    [43114]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7', // Avalanche USDT
    [CHAIN_25]: '0x66e4286603D22FF153A6547700f37C7Eae42F8E2', // Cronos USDT
    [42220]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e', // Celo USDT
    [1111]: '0xA649325Aa7C5093d12D6F98EB4378deAe68CE23F', // Wemix USDT
  },
  cUSDC_V2: {
    [CHAIN_138]: '0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d',
  },
  cUSDT_V2: {
    [CHAIN_138]: '0x9FBfab33882Efe0038DAa608185718b772EE5660',
  },
  cUSDW: {
    [CHAIN_138]: '0xcA6BFa614935f1AB71c9aB106bAA6FBB6057095e',
  },
  // ALL / AUSDT corridor hub on Chain 138 (see config/smart-contracts-master.json COMPLIANT_AUSDT_ADDRESS)
  cAUSDT: {
    [CHAIN_138]: '0x5fdDF65733e3d590463F68f93Cf16E8c04081271',
  },
  cBTC: {
    [CHAIN_138]: '0xcb7c000000000000000000000000000000000138',
  },
  cETH: {
    [CHAIN_138]: '0xce7e00000000000000000000000000000000008a',
  },
  cETHL2: {
    [CHAIN_138]: '0xce7200000000000000000000000000000000008a',
  },
  cBNB: {
    [CHAIN_138]: '0xcb6b00000000000000000000000000000000008a',
  },
  cPOL: {
    [CHAIN_138]: '0xc90100000000000000000000000000000000008a',
  },
  cAVAX: {
    [CHAIN_138]: '0xcaaa00000000000000000000000000000000008a',
  },
  cCRO: {
    [CHAIN_138]: '0xcc2000000000000000000000000000000000008a',
  },
  cXDAI: {
    [CHAIN_138]: '0xcda100000000000000000000000000000000008a',
  },
  cCELO: {
    [CHAIN_138]: '0xcce100000000000000000000000000000000008a',
  },
  cWEMIX: {
    [CHAIN_138]: '0xc11100000000000000000000000000000000008a',
  },
  cWAUSDT: {
    [56]: '0xe1a51Bc037a79AB36767561B147eb41780124934',
    [137]: '0xf12e262F85107df26741726b074606CaFa24AAe7',
    [43114]: '0xff3084410A732231472Ee9f93F5855dA89CC5254',
    [42220]: '0xC158b6cD3A3088C52F797D41f5Aa02825361629e',
  },
  cWUSDC: {
    [1]: '0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a',
    [56]: '0x5355148C4740fcc3D7a96F05EdD89AB14851206b',
    [137]: '0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4',
    [100]: '0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4',
    [10]: '0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105',
    [42161]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF',
    [8453]: '0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105',
    [43114]: '0x0C242b513008Cd49C89078F5aFb237A3112251EB',
    [42220]: '0x4C38F9A5ed68A04cd28a72E8c68C459Ec34576f3',
  },
  cWUSDT: {
    [1]: '0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE',
    [56]: '0x9a1D0dBEE997929ED02fD19E0E199704d20914dB',
    [137]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF',
    [100]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF',
    [10]: '0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6',
    [42161]: '0x73ADaF7dBa95221c080db5631466d2bC54f6a76B',
    [8453]: '0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6',
    [43114]: '0x8142BA530B08f3950128601F00DaaA678213DFdf',
    [42220]: '0x73376eB92c16977B126dB9112936A20Fa0De3442',
  },
  cWUSDW: {
    [56]: '0xC2FA05F12a75Ac84ea778AF9D6935cA807275E55',
    [43114]: '0xcfdCe5E660FC2C8052BDfa7aEa1865DD753411Ae',
  },
  cWBTC: {
    [1]: '0xcb7c000000000000000000000000000000000001',
    [10]: '0xcb7c00000000000000000000000000000000000a',
    [25]: '0xcb7c000000000000000000000000000000000019',
    [56]: '0xcb7c000000000000000000000000000000000038',
    [100]: '0xcb7c000000000000000000000000000000000064',
    [137]: '0xcb7c000000000000000000000000000000000089',
    [1111]: '0xcb7c000000000000000000000000000000000457',
    [8453]: '0xcb7c000000000000000000000000000000002105',
    [42161]: '0xcb7c00000000000000000000000000000000a4b1',
    [42220]: '0xcb7c00000000000000000000000000000000a4ec',
    [43114]: '0xcb7c00000000000000000000000000000000a86a',
  },
  cWETH: {
    [1]: '0xce7e000000000000000000000000000000000001',
  },
  cWETHL2: {
    [10]: '0xce7200000000000000000000000000000000000a',
    [42161]: '0xce7200000000000000000000000000000000a4b1',
    [8453]: '0xce72000000000000000000000000000000002105',
  },
  cWBNB: {
    [56]: '0xcb6b000000000000000000000000000000000038',
  },
  cWPOL: {
    [137]: '0xc901000000000000000000000000000000000089',
  },
  cWAVAX: {
    [43114]: '0xcaaa00000000000000000000000000000000a86a',
  },
  cWCRO: {
    [25]: '0xcc20000000000000000000000000000000000019',
  },
  cWXDAI: {
    [100]: '0xcda1000000000000000000000000000000000064',
  },
  cWCELO: {
    [42220]: '0xcce100000000000000000000000000000000a4ec',
  },
  cWWEMIX: {
    [1111]: '0xc111000000000000000000000000000000000457',
  },
  // Compliant Fiat on Chain 138 — from DeployCompliantFiatTokens (2026-02-27)
  cEURC: { [CHAIN_138]: '0x8085961F9cF02b4d800A3c6d386D31da4B34266a' },
  cEURT: { [CHAIN_138]: '0xdf4b71c61E5912712C1Bdd451416B9aC26949d72' },
  cGBPC: { [CHAIN_138]: '0x003960f16D9d34F2e98d62723B6721Fb92074aD2' },
  cGBPT: { [CHAIN_138]: '0x350f54e4D23795f86A9c03988c7135357CCaD97c' },
  cAUDC: { [CHAIN_138]: '0xD51482e567c03899eecE3CAe8a058161FD56069D' },
  cJPYC: { [CHAIN_138]: '0xEe269e1226a334182aace90056EE4ee5Cc8A6770' },
  cCHFC: { [CHAIN_138]: '0x873990849DDa5117d7C644f0aF24370797C03885' },
  cCADC: { [CHAIN_138]: '0x54dBd40cF05e15906A2C21f600937e96787f5679' },
  cXAUC: { [CHAIN_138]: '0x290E52a8819A4fbD0714E517225429aA2B70EC6b' },
  cXAUT: { [CHAIN_138]: '0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E' },
  WETH: { [CHAIN_138]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' },
  WETH10: { [CHAIN_138]: '0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f' },
  // ISO-4217W on Cronos (25) — from DeployISO4217WSystem
  USDW: { [CHAIN_25]: '0x948690147D2e50ffe50C5d38C14125aD6a9FA036' },
  EURW: { [CHAIN_25]: '0x58a8D8F78F1B65c06dAd7542eC46b299629A60dd' },
  GBPW: { [CHAIN_25]: '0xFb4B6Cc81211F7d886950158294A44C312abCA29' },
  AUDW: { [CHAIN_25]: '0xf9f5D0ACD71C76F9476F10B3F3d3E201F0883C68' },
  JPYW: { [CHAIN_25]: '0xeE17bB0322383fecCA2784fbE2d4CD7d02b1905B' },
  CHFW: { [CHAIN_25]: '0xc9750828124D4c10e7a6f4B655cA8487bD3842EB' },
  CADW: { [CHAIN_25]: '0x328Cd365Bb35524297E68ED28c6fF2C9557d1363' },
};

function normalizeAddress(address?: string | null): string {
  return typeof address === 'string' ? address.trim().toLowerCase() : '';
}

function getGruTransportCanonicalToken(symbol: string): GruTransportCanonicalToken | null {
  const loader = loadTokenMappingLoader<{
    getEnabledCanonicalToken?: (identifier: string) => GruTransportCanonicalToken | null;
  }>();
  return loader?.getEnabledCanonicalToken?.(symbol) ?? null;
}

function getTransportLookup(symbol: string): { baseSymbol: string; version: 'v1' | 'v2' } | null {
  if (symbol === 'cUSDT' || symbol === 'cUSDC') {
    return { baseSymbol: symbol, version: 'v1' };
  }
  if (symbol === 'cUSDT_V2') {
    return { baseSymbol: 'cUSDT', version: 'v2' };
  }
  if (symbol === 'cUSDC_V2') {
    return { baseSymbol: 'cUSDC', version: 'v2' };
  }
  return null;
}

function getTransportDeploymentAddress(symbol: string, version: 'v1' | 'v2'): string | undefined {
  const token = getGruTransportCanonicalToken(symbol);
  if (!token) return undefined;

  const deploymentMatch = Array.isArray(token.deployments)
    ? token.deployments.find((deployment) => String(deployment.version || '').trim().toLowerCase() === version)
    : null;
  if (deploymentMatch?.address) return deploymentMatch.address;

  if (version === 'v1') {
    if (String(token.activeVersion || '').trim().toLowerCase() === 'v1' && token.activeAddress) {
      return token.activeAddress;
    }
  } else if (String(token.x402PreferredVersion || '').trim().toLowerCase() === 'v2' && token.x402PreferredAddress) {
    return token.x402PreferredAddress;
  }

  return undefined;
}

function addr(symbol: string, chainId: number): string | undefined {
  if (chainId === CHAIN_138 && symbol === 'USDT') {
    return process.env.USDT_ADDRESS_138 || process.env.OFFICIAL_USDT_ADDRESS || FALLBACK_ADDRESSES[symbol]?.[chainId];
  }
  if (chainId === CHAIN_138 && symbol === 'USDC') {
    return process.env.USDC_ADDRESS_138 || process.env.OFFICIAL_USDC_ADDRESS || FALLBACK_ADDRESSES[symbol]?.[chainId];
  }
  if (chainId === CHAIN_138) {
    const transportLookup = getTransportLookup(symbol);
    if (transportLookup) {
      const envKey = `${symbol.replace(/-/g, '_').toUpperCase()}_ADDRESS_${chainId}`;
      const envVal = process.env[envKey];
      if (envVal && envVal.trim() !== '') return envVal;
      return (
        getTransportDeploymentAddress(transportLookup.baseSymbol, transportLookup.version) ||
        FALLBACK_ADDRESSES[symbol]?.[chainId]
      );
    }
  }
  const key = `${symbol.replace(/-/g, '_').toUpperCase()}_ADDRESS_${chainId}`;
  const envVal = process.env[key];
  if (envVal && envVal.trim() !== '') return envVal;
  const legacySuffix = LEGACY_CHAIN_ENV_SUFFIX[chainId];
  if (legacySuffix) {
    const legacyKey = `${symbol.replace(/-/g, '_').toUpperCase()}_${legacySuffix}`;
    const legacyVal = process.env[legacyKey];
    if (legacyVal && legacyVal.trim() !== '') return legacyVal;
  }
  return FALLBACK_ADDRESSES[symbol]?.[chainId];
}

export const CANONICAL_TOKENS: CanonicalTokenSpec[] = [
  // --- Base (GRU-M1) ---
  // Local Chain 138 quote-side mirror stables used by PMM pools.
  { symbol: 'USDC', name: 'USD Coin (Official Mirror)', type: 'base', decimals: 6, currencyCode: 'USD', addresses: { [CHAIN_138]: addr('USDC', CHAIN_138) || '' } },
  { symbol: 'USDT', name: 'Tether USD (Official Mirror)', type: 'base', decimals: 6, currencyCode: 'USD', addresses: { [CHAIN_138]: addr('USDT', CHAIN_138) || '' } },
  // Chain 138 v0 only (no X): cUSDC on 138; cXUSDC used only for bridged/origin reference elsewhere. See ISO4217_COMPLIANT_TOKEN_MATRIX.md
  { symbol: 'cUSDC', name: 'USD Coin (Compliant)', type: 'base', decimals: 6, currencyCode: 'USD', v0Alias: 'cUSDC', addresses: { [CHAIN_138]: addr('cUSDC', CHAIN_138) || '', [CHAIN_651940]: addr('cUSDC', CHAIN_651940) || '', ...Object.fromEntries(L2_CHAIN_IDS.map((id) => [id, addr('cUSDC', id)])) } },
  { symbol: 'cUSDC_V2', name: 'USD Coin (Compliant V2)', type: 'base', decimals: 6, currencyCode: 'USD', familySymbol: 'cUSDC', deploymentVersion: 'v2', deploymentStatus: 'staged', preferredForX402: true, liquiditySourceSymbol: 'cUSDC', description: 'Chain 138 x402 / permit-capable V2 deployment. Liquidity and PMM routing remain on cUSDC until cutover.', addresses: { [CHAIN_138]: addr('cUSDC_V2', CHAIN_138) || '' } },
  // Chain 138 v0 only (no X): cUSDT on 138; cXUSDT used only for bridged/origin reference elsewhere. See ISO4217_COMPLIANT_TOKEN_MATRIX.md
  { symbol: 'cUSDT', name: 'Tether USD (Compliant)', type: 'base', decimals: 6, currencyCode: 'USD', v0Alias: 'cUSDT', addresses: { [CHAIN_138]: addr('cUSDT', CHAIN_138) || '', [CHAIN_651940]: addr('cUSDT', CHAIN_651940) || '', ...Object.fromEntries(L2_CHAIN_IDS.map((id) => [id, addr('cUSDT', id)])) } },
  { symbol: 'cUSDT_V2', name: 'Tether USD (Compliant V2)', type: 'base', decimals: 6, currencyCode: 'USD', familySymbol: 'cUSDT', deploymentVersion: 'v2', deploymentStatus: 'staged', preferredForX402: true, liquiditySourceSymbol: 'cUSDT', description: 'Chain 138 x402 / permit-capable V2 deployment. Liquidity and PMM routing remain on cUSDT until cutover.', addresses: { [CHAIN_138]: addr('cUSDT_V2', CHAIN_138) || '' } },
  { symbol: 'cAUSDT', name: 'Alltra USD Token (Compliant)', type: 'base', decimals: 6, currencyCode: 'USD', description: 'Live Chain 138 compliant landing asset for the ALL Mainnet AUSDT corridor.', addresses: { [CHAIN_138]: addr('cAUSDT', CHAIN_138) || '' } },
  { symbol: 'cUSDW', name: 'USD W (Compliant)', type: 'base', decimals: 6, currencyCode: 'USD', description: 'Chain 138 repo-native cUSDW hub asset for D-WIN-aligned PMM and cWUSDW transport planning.', addresses: { [CHAIN_138]: addr('cUSDW', CHAIN_138) || '' } },
  {
    symbol: 'cBTC',
    name: 'Bitcoin (Compliant)',
    type: 'base',
    decimals: 8,
    currencyCode: 'BTC',
    registryFamily: 'monetary_unit',
    description: 'Canonical Chain 138 compliant Bitcoin monetary unit with satoshi-precision accounting and custody-backed mint controls.',
    addresses: { [CHAIN_138]: addr('cBTC', CHAIN_138) || '' },
  },
  {
    symbol: 'cETH',
    name: 'Ether Mainnet (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Ethereum mainnet gas inventory. This family remains isolated from the shared ETH L2 family.',
    addresses: { [CHAIN_138]: addr('cETH', CHAIN_138) || '' },
  },
  {
    symbol: 'cETHL2',
    name: 'Ether L2 Basket (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of the shared ETH L2 family across Optimism, Arbitrum, and Base.',
    addresses: { [CHAIN_138]: addr('cETHL2', CHAIN_138) || '' },
  },
  {
    symbol: 'cBNB',
    name: 'BNB (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'BNB',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of BNB gas inventory.',
    addresses: { [CHAIN_138]: addr('cBNB', CHAIN_138) || '' },
  },
  {
    symbol: 'cPOL',
    name: 'POL (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'POL',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Polygon gas inventory.',
    addresses: { [CHAIN_138]: addr('cPOL', CHAIN_138) || '' },
  },
  {
    symbol: 'cAVAX',
    name: 'Avalanche (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'AVAX',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Avalanche gas inventory.',
    addresses: { [CHAIN_138]: addr('cAVAX', CHAIN_138) || '' },
  },
  {
    symbol: 'cCRO',
    name: 'Cronos (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'CRO',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Cronos gas inventory.',
    addresses: { [CHAIN_138]: addr('cCRO', CHAIN_138) || '' },
  },
  {
    symbol: 'cXDAI',
    name: 'xDAI (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'XDAI',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Gnosis Chain xDAI gas inventory.',
    addresses: { [CHAIN_138]: addr('cXDAI', CHAIN_138) || '' },
  },
  {
    symbol: 'cCELO',
    name: 'Celo (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'CELO',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Celo gas inventory.',
    addresses: { [CHAIN_138]: addr('cCELO', CHAIN_138) || '' },
  },
  {
    symbol: 'cWEMIX',
    name: 'Wemix Hub (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'WEMIX',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Wemix gas inventory. The public mirror keeps the distinct cWWEMIX symbol to avoid naming collisions.',
    addresses: { [CHAIN_138]: addr('cWEMIX', CHAIN_138) || '' },
  },
  // Public-network transport mirrors for canonical Chain 138 c* assets.
  { symbol: 'cWAUSDT', name: 'Alltra USD Token (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form for the live Chain 138 cAUSDT surface.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWAUSDT', id)])) } },
  { symbol: 'cWUSDC', name: 'USD Coin (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form of canonical Chain 138 cUSDC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWUSDC', id)])) } },
  { symbol: 'cWUSDT', name: 'Tether USD (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form of canonical Chain 138 cUSDT.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWUSDT', id)])) } },
  { symbol: 'cWUSDW', name: 'USD W (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form of canonical Chain 138 cUSDW.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWUSDW', id)])) } },
  {
    symbol: 'WETH',
    name: 'Wrapped Ether (WETH9)',
    type: 'w',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Legacy WETH9 surface used on Chain 138 for canonical ETH swap routing and CCIP WETH9 bridge lanes.',
    addresses: { [CHAIN_138]: addr('WETH', CHAIN_138) || '' },
  },
  {
    symbol: 'WETH10',
    name: 'Wrapped Ether 10',
    type: 'w',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Chain 138 WETH10 pilot wrapped ETH surface used by DODO v3 routing and flash-capable paths.',
    addresses: { [CHAIN_138]: addr('WETH10', CHAIN_138) || '' },
  },
  {
    symbol: 'cWBTC',
    name: 'Bitcoin (Compliant Wrapped Monetary Unit)',
    type: 'w',
    decimals: 8,
    currencyCode: 'BTC',
    registryFamily: 'monetary_unit',
    description: 'Public-network mirrored transport form of canonical Chain 138 cBTC. Distinct from Ethereum WBTC and other third-party wrapped BTC products.',
    addresses: { ...Object.fromEntries(BTC_CW_CHAIN_IDS.map((id) => [id, addr('cWBTC', id)])) },
  },
  {
    symbol: 'cWETH',
    name: 'Ether Mainnet (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cETH for Ethereum mainnet only.',
    addresses: { ...Object.fromEntries(ETH_MAINNET_CW_CHAIN_IDS.map((id) => [id, addr('cWETH', id)])) },
  },
  {
    symbol: 'cWETHL2',
    name: 'Ether L2 Basket (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cETHL2 across the approved ETH L2 family.',
    addresses: { ...Object.fromEntries(ETH_L2_CW_CHAIN_IDS.map((id) => [id, addr('cWETHL2', id)])) },
  },
  {
    symbol: 'cWBNB',
    name: 'BNB (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'BNB',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cBNB.',
    addresses: { ...Object.fromEntries(BNB_CW_CHAIN_IDS.map((id) => [id, addr('cWBNB', id)])) },
  },
  {
    symbol: 'cWPOL',
    name: 'POL (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'POL',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cPOL.',
    addresses: { ...Object.fromEntries(POL_CW_CHAIN_IDS.map((id) => [id, addr('cWPOL', id)])) },
  },
  {
    symbol: 'cWAVAX',
    name: 'Avalanche (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'AVAX',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cAVAX.',
    addresses: { ...Object.fromEntries(AVAX_CW_CHAIN_IDS.map((id) => [id, addr('cWAVAX', id)])) },
  },
  {
    symbol: 'cWCRO',
    name: 'Cronos (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'CRO',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cCRO.',
    addresses: { ...Object.fromEntries(CRO_CW_CHAIN_IDS.map((id) => [id, addr('cWCRO', id)])) },
  },
  {
    symbol: 'cWXDAI',
    name: 'xDAI (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'XDAI',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cXDAI.',
    addresses: { ...Object.fromEntries(XDAI_CW_CHAIN_IDS.map((id) => [id, addr('cWXDAI', id)])) },
  },
  {
    symbol: 'cWCELO',
    name: 'Celo (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'CELO',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cCELO.',
    addresses: { ...Object.fromEntries(CELO_CW_CHAIN_IDS.map((id) => [id, addr('cWCELO', id)])) },
  },
  {
    symbol: 'cWWEMIX',
    name: 'Wemix (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'WEMIX',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cWEMIX. The doubled W preserves the cW* naming discipline and keeps the canonical hub symbol distinct.',
    addresses: { ...Object.fromEntries(WEMIX_CW_CHAIN_IDS.map((id) => [id, addr('cWWEMIX', id)])) },
  },
  { symbol: 'cEURC', name: 'Euro Coin (Compliant)', type: 'base', decimals: 6, currencyCode: 'EUR', addresses: { [CHAIN_138]: addr('cEURC', CHAIN_138), [CHAIN_651940]: addr('cEURC', CHAIN_651940) } },
  { symbol: 'cEURT', name: 'Tether EUR (Compliant)', type: 'base', decimals: 6, currencyCode: 'EUR', addresses: { [CHAIN_138]: addr('cEURT', CHAIN_138), [CHAIN_651940]: addr('cEURT', CHAIN_651940) } },
  { symbol: 'cGBPC', name: 'Pound Sterling (Compliant)', type: 'base', decimals: 6, currencyCode: 'GBP', addresses: { [CHAIN_138]: addr('cGBPC', CHAIN_138), [CHAIN_651940]: addr('cGBPC', CHAIN_651940) } },
  { symbol: 'cGBPT', name: 'Tether GBP (Compliant)', type: 'base', decimals: 6, currencyCode: 'GBP', addresses: { [CHAIN_138]: addr('cGBPT', CHAIN_138), [CHAIN_651940]: addr('cGBPT', CHAIN_651940) } },
  { symbol: 'cAUDC', name: 'Australian Dollar (Compliant)', type: 'base', decimals: 6, currencyCode: 'AUD', addresses: { [CHAIN_138]: addr('cAUDC', CHAIN_138), [CHAIN_651940]: addr('cAUDC', CHAIN_651940) } },
  { symbol: 'cJPYC', name: 'Japanese Yen (Compliant)', type: 'base', decimals: 6, currencyCode: 'JPY', addresses: { [CHAIN_138]: addr('cJPYC', CHAIN_138), [CHAIN_651940]: addr('cJPYC', CHAIN_651940) } },
  { symbol: 'cCHFC', name: 'Swiss Franc (Compliant)', type: 'base', decimals: 6, currencyCode: 'CHF', addresses: { [CHAIN_138]: addr('cCHFC', CHAIN_138), [CHAIN_651940]: addr('cCHFC', CHAIN_651940) } },
  { symbol: 'cCADC', name: 'Canadian Dollar (Compliant)', type: 'base', decimals: 6, currencyCode: 'CAD', addresses: { [CHAIN_138]: addr('cCADC', CHAIN_138), [CHAIN_651940]: addr('cCADC', CHAIN_651940) } },
  {
    symbol: 'cXAUC',
    name: 'Gold (Compliant)',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    description: '1 full token = 1 troy ounce fine gold (10^6 base units = 1 oz).',
    addresses: { [CHAIN_138]: addr('cXAUC', CHAIN_138) },
  },
  {
    symbol: 'cXAUT',
    name: 'Tether XAU (Compliant)',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    description: '1 full token = 1 troy ounce fine gold (10^6 base units = 1 oz).',
    addresses: { [CHAIN_138]: addr('cXAUT', CHAIN_138) },
  },
  {
    symbol: 'cAXAUC',
    name: 'Alltra Gold Coin',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    description: 'Planned ALL Mainnet native-unwrapped gold landing asset for the 138 -> 651940 corridor.',
    addresses: { [CHAIN_651940]: addr('cAXAUC', CHAIN_651940) || '' },
  },
  {
    symbol: 'cAXAUT',
    name: 'Alltra Tether XAU',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    description: 'Planned ALL Mainnet native-unwrapped XAU token for the 138 -> 651940 corridor.',
    addresses: { [CHAIN_651940]: addr('cAXAUT', CHAIN_651940) || '' },
  },
  {
    symbol: 'cWAXAUC',
    name: 'Alltra Wrapped Gold Coin',
    type: 'w',
    decimals: 6,
    currencyCode: 'XAU',
    description: 'Planned ALL Mainnet bridge-minted wrapped gold representation for inbound Chain 138 cXAUC transport.',
    addresses: { [CHAIN_651940]: addr('cWAXAUC', CHAIN_651940) || '' },
  },
  {
    symbol: 'cWAXAUT',
    name: 'Alltra Wrapped Tether XAU',
    type: 'w',
    decimals: 6,
    currencyCode: 'XAU',
    description: 'Planned ALL Mainnet bridge-minted wrapped XAU representation for inbound Chain 138 cXAUT transport.',
    addresses: { [CHAIN_651940]: addr('cWAXAUT', CHAIN_651940) || '' },
  },
  { symbol: 'LiXAU', name: 'XAU Liquidity-adjusted', type: 'base', decimals: 6, currencyCode: 'XAU', addresses: { [CHAIN_138]: addr('LiXAU', CHAIN_138), [CHAIN_651940]: addr('LiXAU', CHAIN_651940) } },
  // --- ISO-4217 W ---
  { symbol: 'USDW', name: 'USD W Token', type: 'w', decimals: 2, currencyCode: 'USD', addresses: { [CHAIN_138]: addr('USDW', CHAIN_138), [CHAIN_25]: addr('USDW', CHAIN_25), [CHAIN_651940]: addr('USDW', CHAIN_651940) } },
  { symbol: 'EURW', name: 'EUR W Token', type: 'w', decimals: 2, currencyCode: 'EUR', addresses: { [CHAIN_138]: addr('EURW', CHAIN_138), [CHAIN_25]: addr('EURW', CHAIN_25), [CHAIN_651940]: addr('EURW', CHAIN_651940) } },
  { symbol: 'GBPW', name: 'GBP W Token', type: 'w', decimals: 2, currencyCode: 'GBP', addresses: { [CHAIN_138]: addr('GBPW', CHAIN_138), [CHAIN_25]: addr('GBPW', CHAIN_25), [CHAIN_651940]: addr('GBPW', CHAIN_651940) } },
  { symbol: 'AUDW', name: 'AUD W Token', type: 'w', decimals: 2, currencyCode: 'AUD', addresses: { [CHAIN_138]: addr('AUDW', CHAIN_138), [CHAIN_25]: addr('AUDW', CHAIN_25), [CHAIN_651940]: addr('AUDW', CHAIN_651940) } },
  { symbol: 'JPYW', name: 'JPY W Token', type: 'w', decimals: 2, currencyCode: 'JPY', addresses: { [CHAIN_138]: addr('JPYW', CHAIN_138), [CHAIN_25]: addr('JPYW', CHAIN_25), [CHAIN_651940]: addr('JPYW', CHAIN_651940) } },
  { symbol: 'CHFW', name: 'CHF W Token', type: 'w', decimals: 2, currencyCode: 'CHF', addresses: { [CHAIN_138]: addr('CHFW', CHAIN_138), [CHAIN_25]: addr('CHFW', CHAIN_25), [CHAIN_651940]: addr('CHFW', CHAIN_651940) } },
  { symbol: 'CADW', name: 'CAD W Token', type: 'w', decimals: 2, currencyCode: 'CAD', addresses: { [CHAIN_138]: addr('CADW', CHAIN_138), [CHAIN_25]: addr('CADW', CHAIN_25), [CHAIN_651940]: addr('CADW', CHAIN_651940) } },
  // --- Asset (ac*) ---
  { symbol: 'acUSDC', name: 'Deposit cUSDC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acUSDC', CHAIN_138), [CHAIN_651940]: addr('acUSDC', CHAIN_651940) } },
  { symbol: 'acUSDT', name: 'Deposit cUSDT', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acUSDT', CHAIN_138), [CHAIN_651940]: addr('acUSDT', CHAIN_651940) } },
  { symbol: 'acEURC', name: 'Deposit cEURC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acEURC', CHAIN_138), [CHAIN_651940]: addr('acEURC', CHAIN_651940) } },
  { symbol: 'acGBPC', name: 'Deposit cGBPC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acGBPC', CHAIN_138), [CHAIN_651940]: addr('acGBPC', CHAIN_651940) } },
  { symbol: 'acAUDC', name: 'Deposit cAUDC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acAUDC', CHAIN_138), [CHAIN_651940]: addr('acAUDC', CHAIN_651940) } },
  { symbol: 'acJPYC', name: 'Deposit cJPYC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acJPYC', CHAIN_138), [CHAIN_651940]: addr('acJPYC', CHAIN_651940) } },
  { symbol: 'acCHFC', name: 'Deposit cCHFC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acCHFC', CHAIN_138), [CHAIN_651940]: addr('acCHFC', CHAIN_651940) } },
  { symbol: 'acCADC', name: 'Deposit cCADC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acCADC', CHAIN_138), [CHAIN_651940]: addr('acCADC', CHAIN_651940) } },
  { symbol: 'acXAUC', name: 'Deposit cXAUC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acXAUC', CHAIN_138), [CHAIN_651940]: addr('acXAUC', CHAIN_651940) } },
  // --- Debt (vdc* / sdc*) ---
  { symbol: 'vdcUSDC', name: 'Debt cUSDC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcUSDC', CHAIN_138), [CHAIN_651940]: addr('vdcUSDC', CHAIN_651940) } },
  { symbol: 'sdcUSDC', name: 'Debt cUSDC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcUSDC', CHAIN_138), [CHAIN_651940]: addr('sdcUSDC', CHAIN_651940) } },
  { symbol: 'vdcUSDT', name: 'Debt cUSDT (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcUSDT', CHAIN_138), [CHAIN_651940]: addr('vdcUSDT', CHAIN_651940) } },
  { symbol: 'sdcUSDT', name: 'Debt cUSDT (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcUSDT', CHAIN_138), [CHAIN_651940]: addr('sdcUSDT', CHAIN_651940) } },
  { symbol: 'vdcEURC', name: 'Debt cEURC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcEURC', CHAIN_138), [CHAIN_651940]: addr('vdcEURC', CHAIN_651940) } },
  { symbol: 'sdcEURC', name: 'Debt cEURC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcEURC', CHAIN_138), [CHAIN_651940]: addr('sdcEURC', CHAIN_651940) } },
  { symbol: 'vdcGBPC', name: 'Debt cGBPC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcGBPC', CHAIN_138), [CHAIN_651940]: addr('vdcGBPC', CHAIN_651940) } },
  { symbol: 'sdcGBPC', name: 'Debt cGBPC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcGBPC', CHAIN_138), [CHAIN_651940]: addr('sdcGBPC', CHAIN_651940) } },
  { symbol: 'vdcAUDC', name: 'Debt cAUDC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcAUDC', CHAIN_138), [CHAIN_651940]: addr('vdcAUDC', CHAIN_651940) } },
  { symbol: 'sdcAUDC', name: 'Debt cAUDC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcAUDC', CHAIN_138), [CHAIN_651940]: addr('sdcAUDC', CHAIN_651940) } },
  { symbol: 'vdcJPYC', name: 'Debt cJPYC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcJPYC', CHAIN_138), [CHAIN_651940]: addr('vdcJPYC', CHAIN_651940) } },
  { symbol: 'sdcJPYC', name: 'Debt cJPYC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcJPYC', CHAIN_138), [CHAIN_651940]: addr('sdcJPYC', CHAIN_651940) } },
  { symbol: 'vdcCHFC', name: 'Debt cCHFC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcCHFC', CHAIN_138), [CHAIN_651940]: addr('vdcCHFC', CHAIN_651940) } },
  { symbol: 'sdcCHFC', name: 'Debt cCHFC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcCHFC', CHAIN_138), [CHAIN_651940]: addr('sdcCHFC', CHAIN_651940) } },
  { symbol: 'vdcCADC', name: 'Debt cCADC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcCADC', CHAIN_138), [CHAIN_651940]: addr('vdcCADC', CHAIN_651940) } },
  { symbol: 'sdcCADC', name: 'Debt cCADC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcCADC', CHAIN_138), [CHAIN_651940]: addr('sdcCADC', CHAIN_651940) } },
  { symbol: 'vdcXAUC', name: 'Debt cXAUC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcXAUC', CHAIN_138), [CHAIN_651940]: addr('vdcXAUC', CHAIN_651940) } },
  { symbol: 'sdcXAUC', name: 'Debt cXAUC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcXAUC', CHAIN_138), [CHAIN_651940]: addr('sdcXAUC', CHAIN_651940) } },
];

export function getCanonicalTokensByChain(chainId: number): CanonicalTokenSpec[] {
  return CANONICAL_TOKENS.filter(
    (t) => t.addresses[chainId] && String(t.addresses[chainId]).trim() !== ''
  );
}

export function getCanonicalTokenByAddress(chainId: number, address: string): CanonicalTokenSpec | undefined {
  const lower = normalizeAddress(address);
  return CANONICAL_TOKENS.find((t) => t.addresses[chainId]?.toLowerCase() === lower);
}

export function getCanonicalTokenBySymbol(chainId: number, symbol: string): CanonicalTokenSpec | undefined {
  const normalized = symbol.trim().toLowerCase();
  return CANONICAL_TOKENS.find(
    (t) => t.symbol.toLowerCase() === normalized && t.addresses[chainId] && String(t.addresses[chainId]).trim() !== ''
  );
}

export interface CanonicalQuoteAddressResolution {
  requestedAddress: string;
  requestedSymbol?: string;
  lookupAddress: string;
  lookupSymbol?: string;
  usedFallback: boolean;
}

export function resolveCanonicalQuoteAddress(chainId: number, address: string): CanonicalQuoteAddressResolution {
  const requestedAddress = normalizeAddress(address);
  const requestedSpec = getCanonicalTokenByAddress(chainId, requestedAddress);
  if (!requestedSpec) {
    return {
      requestedAddress,
      lookupAddress: requestedAddress,
      usedFallback: false,
    };
  }

  const liquiditySourceSymbol = requestedSpec.liquiditySourceSymbol || requestedSpec.symbol;
  const liquiditySpec = getCanonicalTokenBySymbol(chainId, liquiditySourceSymbol) || requestedSpec;
  const lookupAddress = normalizeAddress(liquiditySpec.addresses[chainId] || requestedAddress);

  return {
    requestedAddress,
    requestedSymbol: requestedSpec.symbol,
    lookupAddress,
    lookupSymbol: liquiditySpec.symbol,
    usedFallback: lookupAddress !== requestedAddress,
  };
}

/** IPFS-hosted logo URLs (Pinata) for Uniswap token list (logoURI).
 * Every token must have logoURI for MetaMask to display icons. getLogoUriForSpec resolves
 * ac-tokens from base (c*), vdc/sdc from base; unknown symbols fall back to ETH_LOGO. */
const IPFS_GATEWAY = 'https://ipfs.io/ipfs';
const GRU_LOGO_BASE =
  'https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru';
const ETH_LOGO = `${IPFS_GATEWAY}/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong`;
const USDC_LOGO = `${GRU_LOGO_BASE}/cUSDC.svg`;
const USDT_LOGO = `${GRU_LOGO_BASE}/cUSDT.svg`;
const BTC_LOGO = 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/bitcoin/info/logo.png';

const LOGO_BY_SYMBOL: Record<string, string> = {
  USDC: USDC_LOGO,
  USDT: USDT_LOGO,
  cUSDC: USDC_LOGO,
  cUSDT: USDT_LOGO,
  cUSDC_V2: USDC_LOGO,
  cUSDT_V2: USDT_LOGO,
  cAUSDT: USDT_LOGO,
  cUSDW: USDC_LOGO,
  cBTC: BTC_LOGO,
  cWAUSDT: USDT_LOGO,
  cWBTC: BTC_LOGO,
  cWUSDC: USDC_LOGO,
  cWUSDT: USDT_LOGO,
  cWUSDW: USDC_LOGO,
  WETH: ETH_LOGO,
  WETH10: ETH_LOGO,
  cEURC: `${GRU_LOGO_BASE}/cEURC.svg`,
  cEURT: `${GRU_LOGO_BASE}/cEURT.svg`,
  cGBPC: `${GRU_LOGO_BASE}/cGBPC.svg`,
  cGBPT: `${GRU_LOGO_BASE}/cGBPT.svg`,
  cAUDC: `${GRU_LOGO_BASE}/cAUDC.svg`,
  cJPYC: `${GRU_LOGO_BASE}/cJPYC.svg`,
  cCHFC: `${GRU_LOGO_BASE}/cCHFC.svg`,
  cCADC: `${GRU_LOGO_BASE}/cCADC.svg`,
  cXAUC: `${GRU_LOGO_BASE}/cXAUC.svg`,
  cXAUT: `${GRU_LOGO_BASE}/cXAUT.svg`,
  cAXAUC: `${GRU_LOGO_BASE}/cXAUC.svg`,
  cAXAUT: `${GRU_LOGO_BASE}/cXAUT.svg`,
  cWAXAUC: `${GRU_LOGO_BASE}/cXAUC.svg`,
  cWAXAUT: `${GRU_LOGO_BASE}/cXAUT.svg`,
  LiXAU: `${IPFS_GATEWAY}/QmUVY5trUM5N1UnS4abReb66fNzGw7kenjU9AjL7TgR3M1`,
  USDW: USDC_LOGO,
  EURW: `${IPFS_GATEWAY}/QmPh16PY241zNtePyeK7ep1uf1RcARV2ynGAuRU8U7sSqS`,
  GBPW: `${IPFS_GATEWAY}/QmT2nJ6WyhYBCsYJ6NfS1BPAqiGKkCEuMxiC8ye93Co1hF`,
  AUDW: `${IPFS_GATEWAY}/Qmb9JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K`,
  JPYW: `${IPFS_GATEWAY}/Qmb9JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K`,
  CHFW: `${IPFS_GATEWAY}/Qmb9JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K`,
  CADW: `${IPFS_GATEWAY}/Qmb9JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K`,
};

/** Resolve logo URI for a canonical token (Uniswap token list format). */
export function getLogoUriForSpec(spec: CanonicalTokenSpec): string {
  if (spec.logoUrl) return spec.logoUrl;
  const bySymbol = LOGO_BY_SYMBOL[spec.symbol];
  if (bySymbol) return bySymbol;
  if (spec.symbol.startsWith('ac')) return getLogoUriForSpec(CANONICAL_TOKENS.find((t) => t.symbol === spec.symbol.replace('ac', 'c')) || spec);
  if (spec.symbol.startsWith('vdc') || spec.symbol.startsWith('sdc')) {
    const base = spec.symbol.replace(/^(vd|sd)c/, 'c');
    return getLogoUriForSpec(CANONICAL_TOKENS.find((t) => t.symbol === base) || spec);
  }
  return ETH_LOGO;
}

export function getTokenRegistryFamily(spec: Pick<CanonicalTokenSpec, 'currencyCode' | 'registryFamily'>): TokenRegistryFamily {
  if (spec.registryFamily) return spec.registryFamily;
  const code = String(spec.currencyCode || '').trim().toUpperCase();
  if (!code) return 'unclassified';
  if (code === 'XAU') return 'commodity';
  if (isISO4217Supported(code)) return 'iso4217';
  if (isMonetaryUnitSupported(code)) return 'monetary_unit';
  return 'unclassified';
}
