/**
 * Cross-chain bridge config for Chain 138 (and optional 651940).
 * Used by cross-chain-indexer for CCIP/Alltra/UniversalCCIP event aggregation.
 */

import { loadTokenMappingLoader } from './repo-config-loader';

export interface BridgeLane {
  destSelector: string;
  destChainId: number;
  destChainName: string;
  bridgeType?: string;
}

export interface BridgeConfig {
  address: string;
  chainId: number;
  type: 'ccip_weth9' | 'ccip_weth10' | 'ccip_stable' | 'alltra' | 'zedxion' | 'universal_ccip';
  tokenSymbol?: string;
  lanes: BridgeLane[];
}

/** Chain 138 bridge addresses from env; lanes can be extended per deployment. */
const chainId138 = 138;

function envAddr(key: string): string {
  const v = process.env[key];
  return typeof v === 'string' && v.startsWith('0x') ? v : '';
}

function envAnyAddr(...keys: string[]): string {
  for (const key of keys) {
    const value = envAddr(key);
    if (value) return value;
  }
  return '';
}

export const CHAIN_138_BRIDGES: BridgeConfig[] = [];
const STABLE_ASSET_SYMBOLS = new Set(['USDT', 'USDC', 'CUSDT', 'CUSDC']);

if (envAddr('CCIPWETH9_BRIDGE_CHAIN138')) {
  CHAIN_138_BRIDGES.push({
    address: envAddr('CCIPWETH9_BRIDGE_CHAIN138'),
    chainId: chainId138,
    type: 'ccip_weth9',
    tokenSymbol: 'WETH',
    lanes: [
      { destSelector: '5009297550715157269', destChainId: 1, destChainName: 'Ethereum' },
      { destSelector: '16015286601757825753', destChainId: 651940, destChainName: 'ALL Mainnet' },
      {
        destSelector: '8481857512324358265',
        destChainId: 143,
        destChainName: 'Monad Mainnet',
        bridgeType: 'ccip_relay_monad',
      },
    ],
  });
}

if (envAddr('CCIPWETH10_BRIDGE_CHAIN138')) {
  CHAIN_138_BRIDGES.push({
    address: envAddr('CCIPWETH10_BRIDGE_CHAIN138'),
    chainId: chainId138,
    type: 'ccip_weth10',
    tokenSymbol: 'WETH',
    lanes: [
      { destSelector: '5009297550715157269', destChainId: 1, destChainName: 'Ethereum' },
      { destSelector: '16015286601757825753', destChainId: 651940, destChainName: 'ALL Mainnet' },
    ],
  });
}

if (envAnyAddr('CCIP_STABLE_BRIDGE_CHAIN138', 'CCIP_STABLECOIN_BRIDGE_CHAIN138')) {
  CHAIN_138_BRIDGES.push({
    address: envAnyAddr('CCIP_STABLE_BRIDGE_CHAIN138', 'CCIP_STABLECOIN_BRIDGE_CHAIN138'),
    chainId: chainId138,
    type: 'ccip_stable',
    tokenSymbol: 'STABLE',
    lanes: [
      { destSelector: '5009297550715157269', destChainId: 1, destChainName: 'Ethereum' },
      { destSelector: '16015286601757825753', destChainId: 651940, destChainName: 'ALL Mainnet' },
    ],
  });
}

if (envAddr('ALLTRA_CUSTOM_BRIDGE_ADDRESS') || envAddr('ALLTRA_ADAPTER_ADDRESS')) {
  const addr = envAddr('ALLTRA_CUSTOM_BRIDGE_ADDRESS') || envAddr('ALLTRA_ADAPTER_ADDRESS');
  CHAIN_138_BRIDGES.push({
    address: addr,
    chainId: chainId138,
    type: 'alltra',
    lanes: [{ destSelector: '0', destChainId: 651940, destChainName: 'ALL Mainnet' }],
  });
}

if (envAnyAddr('ZEDXION_CUSTOM_BRIDGE_138', 'ZEDXION_CUSTOM_BRIDGE', 'ZEDXION_ADAPTER_138')) {
  const addr = envAnyAddr('ZEDXION_CUSTOM_BRIDGE_138', 'ZEDXION_CUSTOM_BRIDGE', 'ZEDXION_ADAPTER_138');
  CHAIN_138_BRIDGES.push({
    address: addr,
    chainId: chainId138,
    type: 'zedxion',
    lanes: [{ destSelector: '0', destChainId: 83872, destChainName: 'ZEDXION' }],
  });
}

if (envAnyAddr('UNIVERSAL_CCIP_BRIDGE_ADDRESS', 'UNIVERSAL_CCIP_BRIDGE')) {
  CHAIN_138_BRIDGES.push({
    address: envAnyAddr('UNIVERSAL_CCIP_BRIDGE_ADDRESS', 'UNIVERSAL_CCIP_BRIDGE'),
    chainId: chainId138,
    type: 'universal_ccip',
    lanes: [
      { destSelector: '5009297550715157269', destChainId: 1, destChainName: 'Ethereum' },
      { destSelector: '16015286601757825753', destChainId: 651940, destChainName: 'ALL Mainnet' },
    ],
  });
}

/** Routing registry entry: path type ALT | CCIP, bridge address, label. Aligns with config/routing-registry.json. */
export interface RoutingRegistryEntry {
  pathType: 'ALT' | 'CCIP' | 'ZEDX';
  bridgeAddress: string;
  bridgeChainId: number;
  label: string;
  fromChain: number;
  toChain: number;
  asset?: string;
}

const ALLTRA_ADAPTER_138 = envAddr('ALLTRA_ADAPTER_ADDRESS') || envAddr('ALLTRA_CUSTOM_BRIDGE_ADDRESS') || '0x66FEBA2fC9a0B47F26DD4284DAd24F970436B8Dc';
const ZEDXION_ADAPTER_138 = envAnyAddr('ZEDXION_ADAPTER_138', 'ZEDXION_CUSTOM_BRIDGE_138', 'ZEDXION_CUSTOM_BRIDGE');
const CCIP_WETH9_138 = envAddr('CCIPWETH9_BRIDGE_CHAIN138') || '0xcacfd227A040002e49e2e01626363071324f820a';
const CCIP_STABLE_138 = envAnyAddr('CCIP_STABLE_BRIDGE_CHAIN138', 'CCIP_STABLECOIN_BRIDGE_CHAIN138');
const UNIVERSAL_CCIP_138 = envAnyAddr('UNIVERSAL_CCIP_BRIDGE_ADDRESS', 'UNIVERSAL_CCIP_BRIDGE');

interface RepoConfigLoader {
  getRoutingRegistryRoutes?: () => RoutingRegistryEntry[];
  getActiveTransportPair?: (
    fromChainId: number,
    toChainId: number,
    criteria?: Record<string, unknown>
  ) => (RoutingRegistryEntry & {
    canonicalSymbol?: string;
    peer?: {
      l1Bridge?: { address?: string; env?: string };
      l2Bridge?: { address?: string; env?: string };
    };
    eligible?: boolean;
  }) | null;
  resolveConfigRef?: (ref?: { address?: string; env?: string }) => string;
}

function loadRepoConfigLoader(): RepoConfigLoader | null {
  return loadTokenMappingLoader<RepoConfigLoader>();
}

function normalizeTransportAsset(asset: string): string {
  const normalized = asset.trim().toLowerCase().replace(/[\s_-]/g, '');
  if (normalized.startsWith('cw')) {
    return `c${normalized.slice(2)}`;
  }
  return normalized;
}

function resolvePeerBridgeAddress(
  loader: RepoConfigLoader | null,
  pair: NonNullable<ReturnType<NonNullable<RepoConfigLoader['getActiveTransportPair']>>>,
  sourceChainId: number
): string {
  const ref = sourceChainId === chainId138 ? pair.peer?.l1Bridge : pair.peer?.l2Bridge;
  const resolved = loader?.resolveConfigRef?.(ref);
  return resolved || '';
}

/**
 * Get routing registry entry for (fromChain, toChain, asset).
 * Used by UI and indexer to choose ALT vs CCIP and to fill routing in activity_events.
 * Canonical registry JSON: repo root config/routing-registry.json.
 */
export function getRouteFromRegistry(
  fromChain: number,
  toChain: number,
  asset: string = 'WETH',
): RoutingRegistryEntry | null {
  if (fromChain === toChain) return null;
  const loader = loadRepoConfigLoader();
  const normalizedAsset = normalizeTransportAsset(asset);

  const activeTransportPair = loader?.getActiveTransportPair?.(fromChain, toChain, { symbol: normalizedAsset });
  if (activeTransportPair) {
    if (activeTransportPair.eligible) {
      const bridgeAddress = resolvePeerBridgeAddress(loader, activeTransportPair, fromChain);
      if (bridgeAddress) {
        return {
          pathType: 'CCIP',
          bridgeAddress,
          bridgeChainId: fromChain === chainId138 ? chainId138 : fromChain,
          label: 'GRUTransport',
          fromChain,
          toChain,
          asset: activeTransportPair.canonicalSymbol || asset,
        };
      }
    }

    // Active GRU transport assets must not silently escape into legacy bridge paths.
    return null;
  }

  const registryRoutes = loader?.getRoutingRegistryRoutes?.() || [];
  const routeMatch =
    registryRoutes.find(
      (route) =>
        route.fromChain === fromChain &&
        route.toChain === toChain &&
        typeof route.asset === 'string' &&
        route.asset.trim().toLowerCase() === asset.trim().toLowerCase()
    ) ||
    registryRoutes.find(
      (route) =>
        route.fromChain === fromChain &&
        route.toChain === toChain &&
        typeof route.asset === 'string' &&
        route.asset.trim().toLowerCase() === normalizedAsset
    );

  if (routeMatch) {
    return routeMatch;
  }

  const is138To651940 = fromChain === 138 && toChain === 651940;
  const is651940To138 = fromChain === 651940 && toChain === 138;
  if (is138To651940 || is651940To138) {
    return {
      pathType: 'ALT',
      bridgeAddress: ALLTRA_ADAPTER_138,
      bridgeChainId: fromChain === 138 ? 138 : 651940,
      label: 'AlltraAdapter',
      fromChain,
      toChain,
      asset,
    };
  }
  const is138To83872 = fromChain === 138 && toChain === 83872;
  const is83872To138 = fromChain === 83872 && toChain === 138;
  if ((is138To83872 || is83872To138) && ZEDXION_ADAPTER_138) {
    return {
      pathType: 'ZEDX',
      bridgeAddress: ZEDXION_ADAPTER_138,
      bridgeChainId: fromChain === 138 ? 138 : 83872,
      label: 'ZedxionAdapter',
      fromChain,
      toChain,
      asset,
    };
  }
  if (fromChain === 138 || toChain === 138) {
    const legacyNormalizedAsset = asset.trim().toUpperCase();
    const isStableAsset = STABLE_ASSET_SYMBOLS.has(legacyNormalizedAsset);

    if (isStableAsset) {
      if (CCIP_STABLE_138) {
        return {
          pathType: 'CCIP',
          bridgeAddress: CCIP_STABLE_138,
          bridgeChainId: 138,
          label: 'CCIPStableBridge',
          fromChain,
          toChain,
          asset,
        };
      }

      if (UNIVERSAL_CCIP_138) {
        return {
          pathType: 'CCIP',
          bridgeAddress: UNIVERSAL_CCIP_138,
          bridgeChainId: 138,
          label: 'UniversalCCIPBridge',
          fromChain,
          toChain,
          asset,
        };
      }

      return null;
    }

    if (legacyNormalizedAsset !== 'WETH' && UNIVERSAL_CCIP_138) {
      return {
        pathType: 'CCIP',
        bridgeAddress: UNIVERSAL_CCIP_138,
        bridgeChainId: 138,
        label: 'UniversalCCIPBridge',
        fromChain,
        toChain,
        asset,
      };
    }

    return {
      pathType: 'CCIP',
      bridgeAddress: CCIP_WETH9_138,
      bridgeChainId: 138,
      label: 'CCIPWETH9Bridge',
      fromChain,
      toChain,
      asset,
    };
  }
  return null;
}
