import { existsSync, readFileSync } from 'fs';
import { resolve } from 'path';
import { fetchBlockscoutTokenMeta } from './blockscout-token-meta';
import { evaluateSupplyNostroMatch, type SupplyNostroMatchInfo } from './omnl-cash-in-bank-audit';
import { runTripleStateReconcile, type TripleReconcileReport } from './omnl-triple-reconcile';
import { resolveCanonicalPriceUsd } from './canonical-price-oracle';

const CHAIN_138 = 138;
const DEFAULT_CUSDC_ADDRESS = '0xf22258f57794CC8E06237084b353Ab30fFfa640b';

export interface HoLiquidityTripleStateSummary {
  aligned?: boolean;
  breaksCount?: number;
  generatedAt?: string;
}

export interface HoLiquidityPerTokenSample {
  address: string;
  totalSupplyUsd?: number;
  cashInBankUsd?: number;
  supplyNostroMatch?: SupplyNostroMatchInfo;
}

function decimalStringToNumber(value?: string, decimals?: number): number | null {
  if (value == null || value === '') return null;
  const dec = Number.isInteger(decimals) ? Number(decimals) : 18;
  try {
    const raw = BigInt(value);
    const base = 10n ** BigInt(dec);
    const whole = raw / base;
    const frac = raw % base;
    return Number(whole) + Number(frac) / Number(base);
  } catch {
    return null;
  }
}

function readOptionalTripleStateFile(): TripleReconcileReport | null {
  const candidates = [
    process.env.OMNL_TRIPLE_RECONCILE_FILE?.trim(),
    resolve(process.cwd(), 'reports/status/omnl-triple-reconcile-latest.json'),
    process.env.PROXMOX_ROOT
      ? resolve(process.env.PROXMOX_ROOT, 'reports/status/omnl-triple-reconcile-latest.json')
      : '',
  ].filter(Boolean) as string[];

  for (const file of candidates) {
    if (!existsSync(file)) continue;
    try {
      return JSON.parse(readFileSync(file, 'utf8')) as TripleReconcileReport;
    } catch {
      continue;
    }
  }
  return null;
}

export async function loadHoLiquidityTripleStateSummary(): Promise<HoLiquidityTripleStateSummary | undefined> {
  let triple: TripleReconcileReport | null = null;
  try {
    triple = await runTripleStateReconcile(process.env.OMNL_HEALTH_LINE_ID?.trim() || undefined);
  } catch {
    triple = null;
  }

  const fileTriple = readOptionalTripleStateFile();
  if ((!triple || (triple.breaks?.length ?? 0) > 0) && fileTriple) {
    triple = fileTriple;
  } else if (!triple && fileTriple) {
    triple = fileTriple;
  }

  if (!triple) return undefined;

  return {
    aligned: triple.aligned,
    breaksCount: (triple.breaks || []).length,
    generatedAt: triple.generatedAt,
  };
}

export async function loadCusdcPerTokenSample(input: {
  cashInBankUsd: number;
  officeId: number;
}): Promise<HoLiquidityPerTokenSample | undefined> {
  const address = (process.env.CUSDC_ADDRESS_138 || DEFAULT_CUSDC_ADDRESS).toLowerCase();
  const meta = await fetchBlockscoutTokenMeta(CHAIN_138, address);
  const decimals = meta?.decimals ?? 6;
  const supplyUnits = decimalStringToNumber(meta?.totalSupply, decimals);
  const { priceUsd } = resolveCanonicalPriceUsd(CHAIN_138, address);
  const pegPriceUsd = priceUsd != null && priceUsd > 0 ? priceUsd : 1;
  const totalSupplyUsd = supplyUnits != null && supplyUnits > 0 ? supplyUnits * pegPriceUsd : undefined;

  const supplyNostroMatch = evaluateSupplyNostroMatch({
    totalSupplyUsd,
    externalNostroCashUsd: input.cashInBankUsd,
    headOfficeId: input.officeId,
  });

  return {
    address,
    totalSupplyUsd,
    cashInBankUsd: input.cashInBankUsd > 0 ? input.cashInBankUsd : undefined,
    supplyNostroMatch,
  };
}
