/**
 * Token mapping API: exposes config/token-mapping-loader (multichain) when run from monorepo.
 * GET /api/v1/token-mapping?fromChain=138&toChain=651940
 * GET /api/v1/token-mapping/pairs
 */

import { Router, Request, Response } from 'express';
import path from 'path';
import { createRequire } from 'module';
import { cacheMiddleware } from '../middleware/cache';

const router: Router = Router();

/** Repo root (proxmox): when run from token-aggregation cwd, 2 levels up to smom-dbis-138, 1 more to proxmox */
const PROXMOX_ROOT = path.resolve(process.cwd(), '../../..');
const LOADER_PATH = path.join(PROXMOX_ROOT, 'config', 'token-mapping-loader.cjs');
const requireLoader = createRequire(path.join(PROXMOX_ROOT, 'package.json'));

function loadMultichainLoader(): {
  getTokenMappingForPair: (from: number, to: number) => { tokens: unknown[]; addressMapFromTo: Record<string, string>; addressMapToFrom: Record<string, string> } | null;
  getAllMultichainPairs: () => Array<{ fromChainId: number; toChainId: number; notes?: string }>;
  getMappedAddress: (from: number, to: number, addr: string) => string | undefined;
} | null {
  try {
    const loader = requireLoader(LOADER_PATH);
    if (loader?.getTokenMappingForPair && loader?.getAllMultichainPairs && loader?.getMappedAddress) {
      return loader;
    }
  } catch {
    // config not available when run outside monorepo
  }
  return null;
}

/**
 * GET /api/v1/token-mapping?fromChain=138&toChain=651940
 * Returns token mapping for a chain pair (from config/token-mapping-multichain.json).
 */
router.get(
  '/',
  cacheMiddleware(5 * 60 * 1000),
  (req: Request, res: Response) => {
    const fromChain = parseInt(String(req.query.fromChain ?? req.query.from), 10);
    const toChain = parseInt(String(req.query.toChain ?? req.query.to), 10);
    if (!Number.isFinite(fromChain) || !Number.isFinite(toChain)) {
      return res.status(400).json({
        error: 'Missing or invalid fromChain and toChain query params',
        example: '/api/v1/token-mapping?fromChain=138&toChain=651940',
      });
    }

    const loader = loadMultichainLoader();
    if (!loader) {
      return res.status(503).json({
        error: 'Token mapping config not available (run from monorepo with config/token-mapping-multichain.json)',
      });
    }

    const result = loader.getTokenMappingForPair(fromChain, toChain);
    if (!result) {
      return res.status(404).json({
        error: 'No token mapping for this chain pair',
        fromChain,
        toChain,
      });
    }

    return res.json({
      fromChainId: fromChain,
      toChainId: toChain,
      tokens: result.tokens,
      addressMapFromTo: result.addressMapFromTo,
      addressMapToFrom: result.addressMapToFrom,
    });
  }
);

/**
 * GET /api/v1/token-mapping/pairs
 * Returns all defined chain pairs.
 */
router.get(
  '/pairs',
  cacheMiddleware(5 * 60 * 1000),
  (req: Request, res: Response) => {
    const loader = loadMultichainLoader();
    if (!loader) {
      return res.status(503).json({
        error: 'Token mapping config not available (run from monorepo)',
      });
    }
    const pairs = loader.getAllMultichainPairs();
    return res.json({ pairs });
  }
);

/**
 * GET /api/v1/token-mapping/resolve?fromChain=138&toChain=56&address=0x...
 * Returns mapped token address on target chain.
 */
router.get(
  '/resolve',
  cacheMiddleware(5 * 60 * 1000),
  (req: Request, res: Response) => {
    const fromChain = parseInt(String(req.query.fromChain ?? req.query.from), 10);
    const toChain = parseInt(String(req.query.toChain ?? req.query.to), 10);
    const address = String(req.query.address ?? req.query.token ?? '').trim();
    if (!Number.isFinite(fromChain) || !Number.isFinite(toChain) || !address) {
      return res.status(400).json({
        error: 'Missing or invalid fromChain, toChain, or address',
        example: '/api/v1/token-mapping/resolve?fromChain=138&toChain=56&address=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
      });
    }

    const loader = loadMultichainLoader();
    if (!loader) {
      return res.status(503).json({
        error: 'Token mapping config not available (run from monorepo)',
      });
    }

    const mapped = loader.getMappedAddress(fromChain, toChain, address);
    return res.json({
      fromChainId: fromChain,
      toChainId: toChain,
      addressOnSource: address,
      addressOnTarget: mapped ?? null,
    });
  }
);

export default router;
