import { createServer } from 'http';
import express from 'express';
import tokenMappingRoutes from './token-mapping';

jest.mock('../middleware/cache');

function createApp() {
  const app = express();
  app.use('/api/v1/token-mapping', tokenMappingRoutes);
  return app;
}

async function startServer(app: express.Application): Promise<{ server: ReturnType<typeof createServer>; baseUrl: string }> {
  const server = createServer(app);
  await new Promise<void>((resolve) => server.listen(0, () => resolve()));
  const port = (server.address() as { port: number }).port;
  return { server, baseUrl: `http://127.0.0.1:${port}` };
}

describe('Token mapping API with GRU Transport overlay', () => {
  let server: ReturnType<typeof createServer>;
  let baseUrl: string;
  const originalChain138Bridge = process.env.CHAIN138_L1_BRIDGE;
  const originalBscBridge = process.env.CW_BRIDGE_BSC;
  const originalReserveVerifier = process.env.CW_RESERVE_VERIFIER_CHAIN138;
  const originalReserveVault = process.env.CW_STABLECOIN_RESERVE_VAULT;
  const originalReserveSystem = process.env.CW_RESERVE_SYSTEM;
  const originalMaxOutstanding = process.env.CW_MAX_OUTSTANDING_USDT_BSC;
  const originalMainnetBridge = process.env.CW_BRIDGE_MAINNET;
  const originalBtcMainnetOutstanding = process.env.CW_MAX_OUTSTANDING_BTC_MAINNET;
  const originalOptimismBridge = process.env.CW_BRIDGE_OPTIMISM;
  const originalGasHybridVerifier = process.env.CW_GAS_HYBRID_CAP_VERIFIER_CHAIN138;
  const originalGasEscrowVault = process.env.CW_GAS_ESCROW_VAULT_CHAIN138;
  const originalGasTreasurySystem = process.env.CW_GAS_TREASURY_SYSTEM;
  const originalEthL2Outstanding = process.env.CW_MAX_OUTSTANDING_ETH_L2_OPTIMISM;
  const originalEthL2Supply = process.env.CW_GAS_OUTSTANDING_ETH_L2_OPTIMISM;
  const originalEthL2Escrowed = process.env.CW_GAS_ESCROWED_ETH_L2_OPTIMISM;
  const originalEthL2Treasury = process.env.CW_GAS_TREASURY_BACKED_ETH_L2_OPTIMISM;
  const originalEthL2Cap = process.env.CW_GAS_TREASURY_CAP_ETH_L2_OPTIMISM;
  const originalCwL1Bridge = process.env.CW_L1_BRIDGE;
  const originalCwL1BridgeChain138 = process.env.CW_L1_BRIDGE_CHAIN138;

  beforeAll(async () => {
    const started = await startServer(createApp());
    server = started.server;
    baseUrl = started.baseUrl;
  });

  afterEach(() => {
    if (originalChain138Bridge === undefined) {
      delete process.env.CHAIN138_L1_BRIDGE;
    } else {
      process.env.CHAIN138_L1_BRIDGE = originalChain138Bridge;
    }
    if (originalBscBridge === undefined) {
      delete process.env.CW_BRIDGE_BSC;
    } else {
      process.env.CW_BRIDGE_BSC = originalBscBridge;
    }
    if (originalReserveVerifier === undefined) {
      delete process.env.CW_RESERVE_VERIFIER_CHAIN138;
    } else {
      process.env.CW_RESERVE_VERIFIER_CHAIN138 = originalReserveVerifier;
    }
    if (originalReserveVault === undefined) {
      delete process.env.CW_STABLECOIN_RESERVE_VAULT;
    } else {
      process.env.CW_STABLECOIN_RESERVE_VAULT = originalReserveVault;
    }
    if (originalReserveSystem === undefined) {
      delete process.env.CW_RESERVE_SYSTEM;
    } else {
      process.env.CW_RESERVE_SYSTEM = originalReserveSystem;
    }
    if (originalMaxOutstanding === undefined) {
      delete process.env.CW_MAX_OUTSTANDING_USDT_BSC;
    } else {
      process.env.CW_MAX_OUTSTANDING_USDT_BSC = originalMaxOutstanding;
    }
    if (originalMainnetBridge === undefined) {
      delete process.env.CW_BRIDGE_MAINNET;
    } else {
      process.env.CW_BRIDGE_MAINNET = originalMainnetBridge;
    }
    if (originalBtcMainnetOutstanding === undefined) {
      delete process.env.CW_MAX_OUTSTANDING_BTC_MAINNET;
    } else {
      process.env.CW_MAX_OUTSTANDING_BTC_MAINNET = originalBtcMainnetOutstanding;
    }
    for (const [key, value] of Object.entries({
      CW_BRIDGE_OPTIMISM: originalOptimismBridge,
      CW_GAS_HYBRID_CAP_VERIFIER_CHAIN138: originalGasHybridVerifier,
      CW_GAS_ESCROW_VAULT_CHAIN138: originalGasEscrowVault,
      CW_GAS_TREASURY_SYSTEM: originalGasTreasurySystem,
      CW_MAX_OUTSTANDING_ETH_L2_OPTIMISM: originalEthL2Outstanding,
      CW_GAS_OUTSTANDING_ETH_L2_OPTIMISM: originalEthL2Supply,
      CW_GAS_ESCROWED_ETH_L2_OPTIMISM: originalEthL2Escrowed,
      CW_GAS_TREASURY_BACKED_ETH_L2_OPTIMISM: originalEthL2Treasury,
      CW_GAS_TREASURY_CAP_ETH_L2_OPTIMISM: originalEthL2Cap,
    })) {
      if (value === undefined) {
        delete process.env[key];
      } else {
        process.env[key] = value;
      }
    }
    if (originalCwL1Bridge === undefined) {
      delete process.env.CW_L1_BRIDGE;
    } else {
      process.env.CW_L1_BRIDGE = originalCwL1Bridge;
    }
    if (originalCwL1BridgeChain138 === undefined) {
      delete process.env.CW_L1_BRIDGE_CHAIN138;
    } else {
      process.env.CW_L1_BRIDGE_CHAIN138 = originalCwL1BridgeChain138;
    }
  });

  afterAll((done) => {
    server.close(done);
  });

  it('returns the active GRU transport overlay', async () => {
    const res = await fetch(`${baseUrl}/api/v1/token-mapping/transport/active`);
    expect(res.status).toBe(200);
    const body = (await res.json()) as Record<string, unknown>;
    expect(body.system).toMatchObject({
      name: 'GRU Monetary Transport Layer',
      shortName: 'GRU Transport',
    });
    expect(Array.isArray(body.transportPairs)).toBe(true);
    expect((body.transportPairs as unknown[]).length).toBeGreaterThan(0);
    expect(body.counts).toMatchObject({
      transportPairs: expect.any(Number),
      runtimeReadyTransportPairs: expect.any(Number),
    });
  });

  it('resolves active cUSDT transport from Chain 138 to BSC', async () => {
    process.env.CHAIN138_L1_BRIDGE = '0x3333333333333333333333333333333333333333';
    process.env.CW_BRIDGE_BSC = '0x4444444444444444444444444444444444444444';
    process.env.CW_RESERVE_VERIFIER_CHAIN138 = '0x5555555555555555555555555555555555555555';
    process.env.CW_STABLECOIN_RESERVE_VAULT = '0x6666666666666666666666666666666666666666';
    process.env.CW_RESERVE_SYSTEM = '0x7777777777777777777777777777777777777777';
    process.env.CW_MAX_OUTSTANDING_USDT_BSC = '1000000';

    const source = '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22';
    const res = await fetch(
      `${baseUrl}/api/v1/token-mapping/resolve?fromChain=138&toChain=56&address=${source}`
    );

    expect(res.status).toBe(200);
    const body = (await res.json()) as Record<string, unknown>;
    expect(body.addressOnTarget).toBe('0x9a1D0dBEE997929ED02fD19E0E199704d20914dB');
    expect(body.activeTransportEligible).toBe(true);
    expect(body.gruTransportRuntimeReady).toBe(true);
    expect(body.gruTransportPairKey).toBe('138-56-cUSDT-cWUSDT');
    expect(body.gruTransportCanonicalToken).toMatchObject({
      symbol: 'cUSDT',
      activeVersion: 'v1',
      x402PreferredVersion: 'v2',
    });
  });

  it('resolves active cBTC transport from Chain 138 to Ethereum mainnet', async () => {
    process.env.CHAIN138_L1_BRIDGE = '0x3333333333333333333333333333333333333333';
    process.env.CW_BRIDGE_MAINNET = '0x4444444444444444444444444444444444444444';
    process.env.CW_RESERVE_VERIFIER_CHAIN138 = '0x5555555555555555555555555555555555555555';
    process.env.CW_STABLECOIN_RESERVE_VAULT = '0x6666666666666666666666666666666666666666';
    process.env.CW_RESERVE_SYSTEM = '0x7777777777777777777777777777777777777777';
    process.env.CW_MAX_OUTSTANDING_BTC_MAINNET = '2100000000000000';

    const source = '0xcb7c000000000000000000000000000000000138';
    const res = await fetch(
      `${baseUrl}/api/v1/token-mapping/resolve?fromChain=138&toChain=1&address=${source}`
    );

    expect(res.status).toBe(200);
    const body = (await res.json()) as Record<string, unknown>;
    expect(body.addressOnTarget).toBe('0xcb7c000000000000000000000000000000000001');
    expect(body.activeTransportEligible).toBe(true);
    expect(body.gruTransportRuntimeReady).toBe(true);
    expect(body.gruTransportPairKey).toBe('138-1-cBTC-cWBTC');
  });

  it('resolves gas-family transport metadata for the shared ETH L2 lane', async () => {
    process.env.CHAIN138_L1_BRIDGE = '0x3333333333333333333333333333333333333333';
    process.env.CW_BRIDGE_OPTIMISM = '0x4444444444444444444444444444444444444444';
    process.env.CW_GAS_HYBRID_CAP_VERIFIER_CHAIN138 = '0x5555555555555555555555555555555555555555';
    process.env.CW_GAS_ESCROW_VAULT_CHAIN138 = '0x6666666666666666666666666666666666666666';
    process.env.CW_GAS_TREASURY_SYSTEM = '0x7777777777777777777777777777777777777777';
    process.env.CW_MAX_OUTSTANDING_ETH_L2_OPTIMISM = '125';
    process.env.CW_GAS_OUTSTANDING_ETH_L2_OPTIMISM = '125';
    process.env.CW_GAS_ESCROWED_ETH_L2_OPTIMISM = '100';
    process.env.CW_GAS_TREASURY_BACKED_ETH_L2_OPTIMISM = '25';
    process.env.CW_GAS_TREASURY_CAP_ETH_L2_OPTIMISM = '25';

    /** Matches token-mapping-multichain.json 138→10 Compliant_ETH_L2_cW (not FALLBACK cETHL2 placeholder). */
    const source = '0x18a6b163d255cc0cb32b99697843b487d059907d';
    const res = await fetch(
      `${baseUrl}/api/v1/token-mapping/resolve?fromChain=138&toChain=10&address=${source}`
    );

    expect(res.status).toBe(200);
    const body = (await res.json()) as Record<string, unknown>;
    expect(body.addressOnTarget).toBe('0x95007ec50d0766162f77848edf7bdc4eba147fb4');
    expect(body.activeTransportEligible).toBe(true);
    expect(body.gruTransportRuntimeReady).toBe(true);
    expect(body.gruTransportPairKey).toBe('138-10-cETHL2-cWETHL2');
    expect(body.gruTransportAssetClass).toBe('gas_native');
    expect(body.gruTransportFamilyKey).toBe('eth_l2');
    expect(body.gruTransportBackingMode).toBe('hybrid_cap');
    expect(body.gruTransportRedeemPolicy).toBe('family_fungible_inventory_gated');
  });
});
