import { formatUnits } from 'ethers';
import { getCanonicalTokenByAddress } from '../config/canonical-tokens';
import { getCanonicalPriceUsd } from './canonical-price-oracle';

const CHAIN_138 = 138;

export interface Chain138DodoLiquidityUsd {
  reserve0Usd: number;
  reserve1Usd: number;
  totalLiquidityUsd: number;
}

function normalizeAddress(value?: string): string {
  return String(value || '').trim().toLowerCase();
}

function decimalsForAddress(address: string): number {
  const spec = getCanonicalTokenByAddress(CHAIN_138, normalizeAddress(address));
  return Number(spec?.decimals ?? 18);
}

function parseAmount(value: bigint, decimals: number): number {
  if (value <= 0n) return 0;
  const parsed = Number(formatUnits(value, decimals));
  return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
}

function parsePrice(price?: bigint): number {
  if (!price || price <= 0n) return 0;
  const parsed = Number(formatUnits(price, 18));
  return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
}

export function estimateChain138DodoLiquidityUsd(args: {
  token0Address: string;
  token1Address: string;
  reserve0: bigint;
  reserve1: bigint;
  price?: bigint;
}): Chain138DodoLiquidityUsd {
  const token0Address = normalizeAddress(args.token0Address);
  const token1Address = normalizeAddress(args.token1Address);
  const reserve0Amount = parseAmount(args.reserve0, decimalsForAddress(token0Address));
  const reserve1Amount = parseAmount(args.reserve1, decimalsForAddress(token1Address));
  const price = parsePrice(args.price);

  if (reserve0Amount <= 0 || reserve1Amount <= 0) {
    return { reserve0Usd: 0, reserve1Usd: 0, totalLiquidityUsd: 0 };
  }

  let token0PriceUsd = getCanonicalPriceUsd(CHAIN_138, token0Address) ?? 0;
  let token1PriceUsd = getCanonicalPriceUsd(CHAIN_138, token1Address) ?? 0;

  if (price > 0) {
    if (token1PriceUsd === 1 && token0PriceUsd !== 1) {
      token0PriceUsd = price;
    }
    if (token0PriceUsd === 1 && token1PriceUsd !== 1) {
      token1PriceUsd = price;
    }
  }

  if (token0PriceUsd <= 0 || token1PriceUsd <= 0) {
    return { reserve0Usd: 0, reserve1Usd: 0, totalLiquidityUsd: 0 };
  }

  const reserve0Usd = reserve0Amount * token0PriceUsd;
  const reserve1Usd = reserve1Amount * token1PriceUsd;

  return {
    reserve0Usd,
    reserve1Usd,
    totalLiquidityUsd: reserve0Usd + reserve1Usd,
  };
}
