import type { MoneyLayer, MoneySupplySnapshot } from './types';

/** IPSAS GL mapping for OMNL central-bank money aggregates */
export const GL_CODES = {
  M0_RESERVE: '1050',
  M1_LIABILITY: '2000',
  M1_CIRCULATING: '2100',
  M2_BROAD: '2200',
  SETTLEMENT_SUSPENSE: '1000',
  TRADE_FINANCE_CONTINGENT: '1410',
  CRYPTO_TOKEN_LIABILITY: '2300',
} as const;

/** Policy caps from hybx-omnl-policy (1.2× M0 reserve → M1 capacity; 5× M1 → M2 broad) */
export const POLICY = {
  M0_BACKING_MULTIPLIER: 1.2,
  M1_CAP_MULTIPLIER: 5,
  M2_META_FIAT_RAIL_CONVERSION: true,
} as const;

export function aggregateMetaFiatLayers(
  layers: Partial<Record<MoneyLayer, string>>,
): { metaFiatTotal: string; breakdown: Record<MoneyLayer, string> } {
  const breakdown: Record<MoneyLayer, string> = {
    M0: layers.M0 ?? '0',
    M1: layers.M1 ?? '0',
    M2: layers.M2 ?? '0',
    M00: layers.M00 ?? '0',
  };
  const sum = [breakdown.M0, breakdown.M1, breakdown.M2]
    .map((v) => parseFloat(v) || 0)
    .reduce((a, b) => a + b, 0);
  return { metaFiatTotal: sum.toFixed(2), breakdown };
}

export function buildMoneySupplySnapshot(
  officeId: number,
  balances: Partial<Record<string, string>>,
): MoneySupplySnapshot {
  const m0 = balances[GL_CODES.M0_RESERVE] ?? '0';
  const m1 = balances[GL_CODES.M1_CIRCULATING] ?? '0';
  const m2 = balances[GL_CODES.M2_BROAD] ?? '0';
  const pending = balances[GL_CODES.SETTLEMENT_SUSPENSE] ?? '0';
  const m0Num = parseFloat(m0) || 0;
  const m1Num = parseFloat(m1) || 0;
  return {
    asOf: new Date().toISOString(),
    officeId,
    M0: {
      gl1050: m0,
      backingRatio: POLICY.M0_BACKING_MULTIPLIER,
    },
    M1: {
      circulating: m1,
      gl2000: balances[GL_CODES.M1_LIABILITY] ?? m1,
      gl2100: m1,
      capMultiple: POLICY.M1_CAP_MULTIPLIER,
    },
    M2: {
      broadMoney: m2,
      gl2200: m2,
      metaFiatPending: pending,
    },
    metaFiatRealRail: {
      pendingSettlement: pending,
      inFlightSwift: balances['inFlightSwift'] ?? '0',
    },
  };
}

export function m2FiatToTokenLoadAmount(fiatAmount: string, m2Available: string): {
  loadAmount: string;
  fullyBacked: boolean;
} {
  const fiat = parseFloat(fiatAmount) || 0;
  const m2 = parseFloat(m2Available) || 0;
  const load = Math.min(fiat, m2);
  return {
    loadAmount: load.toFixed(2),
    fullyBacked: load >= fiat && fiat > 0,
  };
}
