export type DexType = 'uniswap_v2' | 'uniswap_v3' | 'sushiswap' | 'dodo' | 'custom';

export interface UniswapV2Config {
  factory: string;
  router: string;
  startBlock: number;
}

export interface UniswapV3Config {
  factory: string;
  router: string;
  startBlock: number;
}

export interface DodoConfig {
  poolManager?: string; // DODO PoolManager contract (allPools + poolRegistry ABI)
  dodoPmmIntegration?: string; // DODOPMMIntegration contract (getAllPools + getPoolConfig + getPoolReserves)
  dodoVendingMachine?: string; // DODO Vending Machine Factory
  dodoApprove?: string; // DODO Approve contract
  startBlock: number;
}

export interface CustomDexConfig {
  factory: string;
  router?: string;
  startBlock: number;
  pairCreatedEvent?: string; // Event signature for pair creation
}

export interface DexFactoryConfig {
  uniswap_v2?: UniswapV2Config[];
  uniswap_v3?: UniswapV3Config[];
  sushiswap?: UniswapV2Config[];
  dodo?: DodoConfig[];
  custom?: CustomDexConfig[];
}

/** Canonical DODOPMMIntegration on Chain 138 — see docs/11-references/CONTRACT_ADDRESSES_REFERENCE.md */
const CANONICAL_CHAIN138_DODO_PMM_INTEGRATION =
  '0x86ADA6Ef91A3B450F89f2b751e93B1b7A3218895';

/** Live Chain 138 DEX defaults — overridden by CHAIN_138_* env when set */
const CHAIN138_DEX_DEFAULTS = {
  uniswap_v2: {
    factory: '0x0C30F6e67Ab3667fCc2f5CEA8e274ef1FB920279',
    router: '0x3019A7fDc76ba7F64F18d78e66842760037ee638',
    startBlock: 4041469,
  },
  uniswap_v3: {
    factory: '0x2f7219276e3ce367dB9ec74C1196a8ecEe67841C',
    router: '0xde9cD8ee2811E6E64a41D5F68Be315d33995975E',
    startBlock: 4041400,
  },
  sushiswap: {
    factory: '0x2871207ff0d56089D70c0134d33f1291B6Fce0BE',
    router: '0xB37b93D38559f53b62ab020A14919f2630a1aE34',
    startBlock: 4041495,
  },
} as const;

function getUniswapV2Config(chainId: number): UniswapV2Config[] | undefined {
  const factory =
    process.env[`CHAIN_${chainId}_UNISWAP_V2_FACTORY`] ||
    (chainId === 138 ? CHAIN138_DEX_DEFAULTS.uniswap_v2.factory : undefined);
  if (!factory) return undefined;

  const defaults = chainId === 138 ? CHAIN138_DEX_DEFAULTS.uniswap_v2 : undefined;
  return [
    {
      factory,
      router:
        process.env[`CHAIN_${chainId}_UNISWAP_V2_ROUTER`] || defaults?.router || '',
      startBlock: parseInt(
        process.env[`CHAIN_${chainId}_UNISWAP_V2_START_BLOCK`] ||
          String(defaults?.startBlock ?? 0),
        10
      ),
    },
  ];
}

function getDodoConfig(chainId: number): DodoConfig[] | undefined {
  const poolManager = process.env[`CHAIN_${chainId}_DODO_POOL_MANAGER`] || '';
  const dodoPmmIntegration = process.env[`CHAIN_${chainId}_DODO_PMM_INTEGRATION`] || '';

  if (!poolManager && !dodoPmmIntegration) return undefined;

  return [
    {
      poolManager,
      dodoPmmIntegration,
      dodoVendingMachine: process.env[`CHAIN_${chainId}_DODO_VENDING_MACHINE`] || '',
      startBlock: parseInt(process.env[`CHAIN_${chainId}_DODO_START_BLOCK`] || '0', 10),
    },
  ];
}

export const DEX_FACTORIES: Record<number, DexFactoryConfig> = {
  138: {
    // DODO PMM Integration - index from DODOPMMIntegration or PoolManager
    dodo: [
      {
        poolManager: process.env.CHAIN_138_DODO_POOL_MANAGER || '',
        dodoPmmIntegration:
          process.env.CHAIN_138_DODO_PMM_INTEGRATION || CANONICAL_CHAIN138_DODO_PMM_INTEGRATION,
        dodoVendingMachine: process.env.CHAIN_138_DODO_VENDING_MACHINE || '',
        startBlock: 0,
      },
    ],
    // UniswapV2 - if deployed
    uniswap_v2: getUniswapV2Config(138),
    // UniswapV3 — live on Chain 138 (defaults from address inventory)
    uniswap_v3: (() => {
      const factory =
        process.env.CHAIN_138_UNISWAP_V3_FACTORY || CHAIN138_DEX_DEFAULTS.uniswap_v3.factory;
      return [
        {
          factory,
          router:
            process.env.CHAIN_138_UNISWAP_V3_ROUTER || CHAIN138_DEX_DEFAULTS.uniswap_v3.router,
          startBlock: parseInt(
            process.env.CHAIN_138_UNISWAP_V3_START_BLOCK ||
              String(CHAIN138_DEX_DEFAULTS.uniswap_v3.startBlock),
            10
          ),
        },
      ];
    })(),
    sushiswap: [
      {
        factory: process.env.CHAIN_138_SUSHISWAP_FACTORY || CHAIN138_DEX_DEFAULTS.sushiswap.factory,
        router: process.env.CHAIN_138_SUSHISWAP_ROUTER || CHAIN138_DEX_DEFAULTS.sushiswap.router,
        startBlock: parseInt(
          process.env.CHAIN_138_SUSHISWAP_START_BLOCK ||
            String(CHAIN138_DEX_DEFAULTS.sushiswap.startBlock),
          10
        ),
      },
    ],
  },
  651940: {
    // ALL Mainnet - DEX factories to be discovered/configured
    // These can be set via environment variables or discovered on-chain
    uniswap_v2: getUniswapV2Config(651940),
    uniswap_v3: process.env.CHAIN_651940_UNISWAP_V3_FACTORY
      ? [
          {
            factory: process.env.CHAIN_651940_UNISWAP_V3_FACTORY,
            router: process.env.CHAIN_651940_UNISWAP_V3_ROUTER || '',
            startBlock: parseInt(process.env.CHAIN_651940_UNISWAP_V3_START_BLOCK || '0', 10),
          },
        ]
      : undefined,
    dodo: process.env.CHAIN_651940_DODO_POOL_MANAGER
      ? [
          {
            poolManager: process.env.CHAIN_651940_DODO_POOL_MANAGER,
            dodoVendingMachine: process.env.CHAIN_651940_DODO_VENDING_MACHINE || '',
            startBlock: parseInt(process.env.CHAIN_651940_DODO_START_BLOCK || '0', 10),
          },
        ]
      : undefined,
    custom: process.env.CHAIN_651940_HYDX_FACTORY
      ? [
          {
            factory: process.env.CHAIN_651940_HYDX_FACTORY,
            router: process.env.CHAIN_651940_HYDX_ROUTER || '',
            startBlock: parseInt(process.env.CHAIN_651940_HYDX_START_BLOCK || '0', 10),
            pairCreatedEvent: process.env.CHAIN_651940_HYDX_PAIR_CREATED_EVENT || '',
          },
        ]
      : undefined,
  },
  // cW* edge chains (1, 10, 56, 100, 137): set CHAIN_*_DODO_PMM_INTEGRATION or CHAIN_*_DODO_POOL_MANAGER to index DODO/pools
  1: {
    uniswap_v2: getUniswapV2Config(1),
    dodo: getDodoConfig(1),
  },
  10: {
    uniswap_v2: getUniswapV2Config(10),
    dodo: getDodoConfig(10),
  },
  25: {
    uniswap_v2: getUniswapV2Config(25),
    dodo: getDodoConfig(25),
  },
  56: {
    uniswap_v2: getUniswapV2Config(56),
    dodo: getDodoConfig(56),
  },
  100: {
    uniswap_v2: getUniswapV2Config(100),
    dodo: getDodoConfig(100),
  },
  137: {
    uniswap_v2: getUniswapV2Config(137),
    dodo: getDodoConfig(137),
  },
  8453: {
    uniswap_v2: getUniswapV2Config(8453),
    dodo: getDodoConfig(8453),
  },
  42161: {
    uniswap_v2: getUniswapV2Config(42161),
    dodo: getDodoConfig(42161),
  },
  42220: {
    uniswap_v2: getUniswapV2Config(42220),
    dodo: getDodoConfig(42220),
  },
  43114: {
    uniswap_v2: getUniswapV2Config(43114),
    dodo: getDodoConfig(43114),
  },
  1111: {
    uniswap_v2: getUniswapV2Config(1111),
    dodo: getDodoConfig(1111),
  },
};

/**
 * Get DEX factory configuration for a chain
 */
export function getDexFactories(chainId: number): DexFactoryConfig | undefined {
  return DEX_FACTORIES[chainId];
}

/**
 * Check if a DEX type is configured for a chain
 */
export function hasDexType(chainId: number, dexType: DexType): boolean {
  const config = DEX_FACTORIES[chainId];
  if (!config) return false;

  switch (dexType) {
    case 'uniswap_v2':
      return !!config.uniswap_v2 && config.uniswap_v2.length > 0;
    case 'uniswap_v3':
      return !!config.uniswap_v3 && config.uniswap_v3.length > 0;
    case 'sushiswap':
      return !!config.sushiswap && config.sushiswap.length > 0;
    case 'dodo':
      return !!config.dodo && config.dodo.length > 0;
    case 'custom':
      return !!config.custom && config.custom.length > 0;
    default:
      return false;
  }
}

/**
 * Get all configured DEX types for a chain
 */
export function getConfiguredDexTypes(chainId: number): DexType[] {
  const config = DEX_FACTORIES[chainId];
  if (!config) return [];

  const types: DexType[] = [];
  if (hasDexType(chainId, 'uniswap_v2')) types.push('uniswap_v2');
  if (hasDexType(chainId, 'uniswap_v3')) types.push('uniswap_v3');
  if (hasDexType(chainId, 'sushiswap')) types.push('sushiswap');
  if (hasDexType(chainId, 'dodo')) types.push('dodo');
  if (hasDexType(chainId, 'custom')) types.push('custom');

  return types;
}
