import {
  getCanonicalTokenByAddress,
  getCanonicalTokenBySymbol,
  getTokenRegistryFamily,
  resolveCanonicalQuoteAddress,
} from './canonical-tokens';

describe('canonical cW token catalog', () => {
  it('models cWUSDT, cWUSDC, cWAUSDT, and cWUSDW as first-class wrapped GRU transport assets', () => {
    const cwUsdt = getCanonicalTokenBySymbol(56, 'cWUSDT');
    expect(cwUsdt).toMatchObject({
      symbol: 'cWUSDT',
      type: 'w',
      currencyCode: 'USD',
    });
    expect(cwUsdt?.addresses[56]).toBe('0x9a1D0dBEE997929ED02fD19E0E199704d20914dB');
    expect(getCanonicalTokenByAddress(56, '0x9a1D0dBEE997929ED02fD19E0E199704d20914dB')?.symbol).toBe('cWUSDT');

    const cwUsdc = getCanonicalTokenBySymbol(8453, 'cWUSDC');
    expect(cwUsdc).toMatchObject({
      symbol: 'cWUSDC',
      type: 'w',
      currencyCode: 'USD',
    });
    expect(cwUsdc?.addresses[8453]).toBe('0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105');
    expect(getCanonicalTokenByAddress(8453, '0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105')?.symbol).toBe('cWUSDC');

    const cwAusdt = getCanonicalTokenBySymbol(56, 'cWAUSDT');
    expect(cwAusdt).toMatchObject({
      symbol: 'cWAUSDT',
      type: 'w',
      currencyCode: 'USD',
    });
    expect(cwAusdt?.addresses[56]).toBe('0xe1a51Bc037a79AB36767561B147eb41780124934');
    expect(getCanonicalTokenByAddress(56, '0xe1a51Bc037a79AB36767561B147eb41780124934')?.symbol).toBe('cWAUSDT');

    const cwUsdw = getCanonicalTokenBySymbol(56, 'cWUSDW');
    expect(cwUsdw).toMatchObject({
      symbol: 'cWUSDW',
      type: 'w',
      currencyCode: 'USD',
    });
    expect(cwUsdw?.addresses[56]).toBe('0xC2FA05F12a75Ac84ea778AF9D6935cA807275E55');
    expect(getCanonicalTokenByAddress(56, '0xC2FA05F12a75Ac84ea778AF9D6935cA807275E55')?.symbol).toBe('cWUSDW');
  });

  it('surfaces cUSDW on Chain 138 as the repo-native USDW hub asset', () => {
    const cusdw = getCanonicalTokenBySymbol(138, 'cUSDW');
    expect(cusdw).toMatchObject({
      symbol: 'cUSDW',
      type: 'base',
      currencyCode: 'USD',
      decimals: 6,
    });
    expect(cusdw?.addresses[138]).toBe('0xcA6BFa614935f1AB71c9aB106bAA6FBB6057095e');
  });

  it('models cBTC and cWBTC as GRU monetary-unit assets with satoshi precision', () => {
    const cbtc = getCanonicalTokenBySymbol(138, 'cBTC');
    expect(cbtc).toMatchObject({
      symbol: 'cBTC',
      type: 'base',
      currencyCode: 'BTC',
      decimals: 8,
    });
    expect(cbtc?.addresses[138]).toBe('0xcb7c000000000000000000000000000000000138');
    expect(getTokenRegistryFamily(cbtc!)).toBe('monetary_unit');

    const cwbtc = getCanonicalTokenBySymbol(1, 'cWBTC');
    expect(cwbtc).toMatchObject({
      symbol: 'cWBTC',
      type: 'w',
      currencyCode: 'BTC',
      decimals: 8,
    });
    expect(cwbtc?.addresses[1]).toBe('0xcb7c000000000000000000000000000000000001');
    expect(getCanonicalTokenByAddress(1, '0xcb7c000000000000000000000000000000000001')?.symbol).toBe('cWBTC');
    expect(getTokenRegistryFamily(cwbtc!)).toBe('monetary_unit');
  });

  it('models gas-native families on Chain 138 and their public cW mirrors with gas-native metadata', () => {
    const ceth = getCanonicalTokenBySymbol(138, 'cETH');
    expect(ceth).toMatchObject({
      symbol: 'cETH',
      type: 'base',
      currencyCode: 'ETH',
      decimals: 18,
    });
    expect(ceth?.addresses[138]).toBe('0xce7e00000000000000000000000000000000008a');
    expect(getTokenRegistryFamily(ceth!)).toBe('gas_native');

    const cethL2 = getCanonicalTokenBySymbol(138, 'cETHL2');
    expect(cethL2).toMatchObject({
      symbol: 'cETHL2',
      type: 'base',
      currencyCode: 'ETH',
      decimals: 18,
    });
    expect(cethL2?.addresses[138]).toBe('0xce7200000000000000000000000000000000008a');

    const cweth = getCanonicalTokenBySymbol(1, 'cWETH');
    expect(cweth).toMatchObject({
      symbol: 'cWETH',
      type: 'w',
      currencyCode: 'ETH',
    });
    expect(cweth?.addresses[1]).toBe('0xce7e000000000000000000000000000000000001');

    const cwethL2 = getCanonicalTokenBySymbol(10, 'cWETHL2');
    expect(cwethL2).toMatchObject({
      symbol: 'cWETHL2',
      type: 'w',
      currencyCode: 'ETH',
    });
    expect(cwethL2?.addresses[10]).toBe('0xce7200000000000000000000000000000000000a');
    expect(getCanonicalTokenByAddress(10, '0xce7200000000000000000000000000000000000a')?.symbol).toBe('cWETHL2');
    expect(getTokenRegistryFamily(cwethL2!)).toBe('gas_native');

    const weth = getCanonicalTokenBySymbol(138, 'WETH');
    expect(weth).toMatchObject({
      symbol: 'WETH',
      type: 'w',
      currencyCode: 'ETH',
      decimals: 18,
    });
    expect(weth?.addresses[138]).toBe('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2');
    expect(getCanonicalTokenByAddress(138, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')?.symbol).toBe('WETH');

    const weth10 = getCanonicalTokenBySymbol(138, 'WETH10');
    expect(weth10).toMatchObject({
      symbol: 'WETH10',
      type: 'w',
      currencyCode: 'ETH',
      decimals: 18,
    });
    expect(weth10?.addresses[138]).toBe('0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f');
    expect(getCanonicalTokenByAddress(138, '0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f')?.symbol).toBe('WETH10');
  });

  it('surfaces cAUSDT on Chain 138 from env and keeps cWAUSDT fallback mirrors on active public chains', () => {
    const previousBase = process.env.CAUSDT_ADDRESS_138;
    process.env.CAUSDT_ADDRESS_138 = '0x2222222222222222222222222222222222222222';
    jest.resetModules();

    const reloaded = require('./canonical-tokens') as typeof import('./canonical-tokens');
    const causdt = reloaded.getCanonicalTokenBySymbol(138, 'cAUSDT');
    const polygonCwAusdt = reloaded.getCanonicalTokenBySymbol(137, 'cWAUSDT');
    const avalancheCwAusdt = reloaded.getCanonicalTokenBySymbol(43114, 'cWAUSDT');
    const celoCwAusdt = reloaded.getCanonicalTokenBySymbol(42220, 'cWAUSDT');

    expect(causdt).toMatchObject({
      symbol: 'cAUSDT',
      type: 'base',
      currencyCode: 'USD',
      decimals: 6,
    });
    expect(causdt?.addresses[138]).toBe('0x2222222222222222222222222222222222222222');
    expect(reloaded.getCanonicalTokenByAddress(138, '0x2222222222222222222222222222222222222222')?.symbol).toBe('cAUSDT');

    expect(polygonCwAusdt).toMatchObject({
      symbol: 'cWAUSDT',
      type: 'w',
      currencyCode: 'USD',
    });
    expect(polygonCwAusdt?.addresses[137]).toBe('0xf12e262F85107df26741726b074606CaFa24AAe7');

    expect(avalancheCwAusdt).toMatchObject({
      symbol: 'cWAUSDT',
      type: 'w',
      currencyCode: 'USD',
    });
    expect(avalancheCwAusdt?.addresses[43114]).toBe('0xff3084410A732231472Ee9f93F5855dA89CC5254');

    expect(celoCwAusdt).toMatchObject({
      symbol: 'cWAUSDT',
      type: 'w',
      currencyCode: 'USD',
    });
    expect(celoCwAusdt?.addresses[42220]).toBe('0xC158b6cD3A3088C52F797D41f5Aa02825361629e');

    if (previousBase === undefined) {
      delete process.env.CAUSDT_ADDRESS_138;
    } else {
      process.env.CAUSDT_ADDRESS_138 = previousBase;
    }
    jest.resetModules();
  });

  it('picks up Polygon cWUSDW from env as soon as the wrapped mirror is deployed', () => {
    const previous = process.env.CWUSDW_ADDRESS_137;
    process.env.CWUSDW_ADDRESS_137 = '0x1111111111111111111111111111111111111111';
    jest.resetModules();

    const reloaded = require('./canonical-tokens') as typeof import('./canonical-tokens');
    const polygonCwUsdw = reloaded.getCanonicalTokenBySymbol(137, 'cWUSDW');

    expect(polygonCwUsdw).toMatchObject({
      symbol: 'cWUSDW',
      type: 'w',
      currencyCode: 'USD',
    });
    expect(polygonCwUsdw?.addresses[137]).toBe('0x1111111111111111111111111111111111111111');
    expect(reloaded.getCanonicalTokenByAddress(137, '0x1111111111111111111111111111111111111111')?.symbol).toBe('cWUSDW');

    if (previous === undefined) {
      delete process.env.CWUSDW_ADDRESS_137;
    } else {
      process.env.CWUSDW_ADDRESS_137 = previous;
    }
    jest.resetModules();
  });

  it('models the Alltra gold exception as env-gated cAXAUC/cAXAUT and cWAXAUC/cWAXAUT on chain 651940', () => {
    const previousCaxauc = process.env.CAXAUC_ADDRESS_651940;
    const previousCwaxauc = process.env.CWAXAUC_ADDRESS_651940;
    process.env.CAXAUC_ADDRESS_651940 = '0x3333333333333333333333333333333333333333';
    process.env.CWAXAUC_ADDRESS_651940 = '0x4444444444444444444444444444444444444444';
    jest.resetModules();

    const reloaded = require('./canonical-tokens') as typeof import('./canonical-tokens');
    const caxauc = reloaded.getCanonicalTokenBySymbol(651940, 'cAXAUC');
    const cwaxauc = reloaded.getCanonicalTokenBySymbol(651940, 'cWAXAUC');
    const cxaucOnAlltra = reloaded.getCanonicalTokenBySymbol(651940, 'cXAUC');

    expect(caxauc).toMatchObject({
      symbol: 'cAXAUC',
      type: 'base',
      currencyCode: 'XAU',
    });
    expect(caxauc?.addresses[651940]).toBe('0x3333333333333333333333333333333333333333');
    expect(reloaded.getCanonicalTokenByAddress(651940, '0x3333333333333333333333333333333333333333')?.symbol).toBe('cAXAUC');

    expect(cwaxauc).toMatchObject({
      symbol: 'cWAXAUC',
      type: 'w',
      currencyCode: 'XAU',
    });
    expect(cwaxauc?.addresses[651940]).toBe('0x4444444444444444444444444444444444444444');
    expect(reloaded.getCanonicalTokenByAddress(651940, '0x4444444444444444444444444444444444444444')?.symbol).toBe('cWAXAUC');

    expect(cxaucOnAlltra).toBeUndefined();

    if (previousCaxauc === undefined) {
      delete process.env.CAXAUC_ADDRESS_651940;
    } else {
      process.env.CAXAUC_ADDRESS_651940 = previousCaxauc;
    }
    if (previousCwaxauc === undefined) {
      delete process.env.CWAXAUC_ADDRESS_651940;
    } else {
      process.env.CWAXAUC_ADDRESS_651940 = previousCwaxauc;
    }
    jest.resetModules();
  });

  it('surfaces Chain 138 V2 x402 deployments explicitly and resolves quote fallback to V1 liquidity', () => {
    const cusdtV1 = getCanonicalTokenBySymbol(138, 'cUSDT');
    const cusdtV2 = getCanonicalTokenBySymbol(138, 'cUSDT_V2');
    const v2Addr = cusdtV2?.addresses[138];
    expect(cusdtV2).toMatchObject({
      symbol: 'cUSDT_V2',
      familySymbol: 'cUSDT',
      deploymentVersion: 'v2',
      preferredForX402: true,
      liquiditySourceSymbol: 'cUSDT',
    });
    expect(v2Addr && String(v2Addr).trim()).toBeTruthy();
    expect(getCanonicalTokenByAddress(138, String(v2Addr))?.symbol).toBe('cUSDT_V2');

    const quoteResolution = resolveCanonicalQuoteAddress(138, String(v2Addr));
    expect(quoteResolution).toMatchObject({
      requestedSymbol: 'cUSDT_V2',
      lookupSymbol: 'cUSDT',
      usedFallback: true,
    });
    expect(quoteResolution.lookupAddress).toBe(String(cusdtV1?.addresses[138] || '').toLowerCase());
  });
});
