import { getCanonicalTokenBySymbol } from '../config/canonical-tokens';
import {
  getCanonicalPriceUsd,
  primeLiveReferencePriceUsd,
  resolveCanonicalPriceUsd,
  resolveCanonicalPriceUsdForSpec,
} from './canonical-price-oracle';

describe('canonical-price-oracle', () => {
  it('pegs Chain 138 USD-family mirrors to one dollar', () => {
    expect(getCanonicalPriceUsd(138, '0x71D6687F38b93CCad569Fa6352c876eea967201b')).toBe(1);
    expect(getCanonicalPriceUsd(138, '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22')).toBe(1);
    expect(getCanonicalPriceUsd(138, '0xf22258f57794CC8E06237084b353Ab30fFfa640b')).toBe(1);
  });

  it('anchors GRU v2 and lending wrappers to the matching c* ISO-4217 asset family', () => {
    const cUsdcV2 = getCanonicalTokenBySymbol(138, 'cUSDC_V2');
    expect(cUsdcV2?.addresses[138]).toBeTruthy();

    expect(resolveCanonicalPriceUsd(138, String(cUsdcV2?.addresses[138]))).toMatchObject({
      priceUsd: 1,
      referenceSymbol: 'USD',
    });

    expect(
      resolveCanonicalPriceUsdForSpec({
        symbol: 'acUSDC',
        name: 'Deposit cUSDC',
        type: 'asset',
        decimals: 6,
        addresses: { 138: '0xac00000000000000000000000000000000000138' },
      })
    ).toMatchObject({
      priceUsd: 1,
      referenceSymbol: 'USD',
    });

    expect(
      resolveCanonicalPriceUsdForSpec({
        symbol: 'vdcEURC',
        name: 'Debt cEURC (variable)',
        type: 'debt',
        decimals: 6,
        addresses: { 138: '0xbdc0000000000000000000000000000000000138' },
      })
    ).toMatchObject({
      priceUsd: 1.1780,
      referenceSymbol: 'EUR',
    });

    expect(
      resolveCanonicalPriceUsdForSpec({
        symbol: 'sdcCADC',
        name: 'Debt cCADC (stable)',
        type: 'debt',
        decimals: 6,
        addresses: { 138: '0xcdc0000000000000000000000000000000000138' },
      })
    ).toMatchObject({
      priceUsd: 0.7255928549430243,
      referenceSymbol: 'CAD',
    });
  });

  it('prices fiat GRU W tokens from the same ISO-4217 oracle references as the c* canonicals', () => {
    const usdw = getCanonicalTokenBySymbol(25, 'USDW');
    const eurw = getCanonicalTokenBySymbol(25, 'EURW');

    expect(usdw?.addresses[25]).toBeTruthy();
    expect(eurw?.addresses[25]).toBeTruthy();

    expect(resolveCanonicalPriceUsd(25, String(usdw?.addresses[25]))).toMatchObject({
      priceUsd: 1,
      referenceSymbol: 'USD',
    });
    expect(resolveCanonicalPriceUsd(25, String(eurw?.addresses[25]))).toMatchObject({
      priceUsd: 1.1780,
      referenceSymbol: 'EUR',
    });
  });

  it('resolves WETH9 and WETH10 to the ETH peg with 18-decimal canonical metadata', () => {
    const weth = resolveCanonicalPriceUsd(138, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2');
    expect(weth).toMatchObject({
      referenceSymbol: 'ETH',
    });
    expect(weth.priceUsd).toBeGreaterThan(0);
    expect(['env', 'on-chain', 'repo-fallback']).toContain(weth.source);

    const weth10 = resolveCanonicalPriceUsd(138, '0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f');
    expect(weth10.referenceSymbol).toBe('ETH');
    expect(weth10.priceUsd).toBeGreaterThan(0);
  });

  it('prefers live on-chain ETH over env when drift exceeds threshold on chain 138', () => {
    process.env.CHAIN138_CANONICAL_PRICE_USD_ETH = '2100';
    primeLiveReferencePriceUsd('ETH', 1772);
    expect(resolveCanonicalPriceUsd(138, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')).toMatchObject({
      priceUsd: 1772,
      referenceSymbol: 'ETH',
      source: 'on-chain',
    });
  });

  it('provides repo-local fallback pegs for commodity and monetary-unit canonicals', () => {
    expect(resolveCanonicalPriceUsd(138, '0x290E52a8819A4fbD0714E517225429aA2B70EC6b')).toMatchObject({
      referenceSymbol: 'XAU',
      source: 'repo-fallback',
    });
    expect(resolveCanonicalPriceUsd(138, '0xe94260c555ac1d9d3cc9e1632883452ebdf0082e')).toMatchObject({
      priceUsd: 90000,
      referenceSymbol: 'BTC',
      source: 'repo-fallback',
    });
  });
});
