import { redondear } from '../common/inm-utils';

/**
 * Reparto de una distribución entre inversores según su participación (M123), por
 * resto mayor: las partes suman exacto lo que corresponde a los inversores. Lo que
 * no cubren las participaciones (si suman menos de 100 %) es de la desarrolladora.
 * Sin cascadas ni preferencias de retorno (fuera de v1, según el spec).
 */
export function repartirPorParticipacion(
  total: number,
  inversores: Array<{ id: string; pct: number }>,
  dec: number,
): { lineas: Array<{ id: string; pct: number; monto: number }>; para_inversores: number; para_desarrolladora: number } {
  const factor = 10 ** dec;
  const validos = inversores.filter((i) => i.pct > 0);
  const sumaPct = validos.reduce((a, i) => a + i.pct, 0);
  const paraInversores = Math.round(((total * Math.min(sumaPct, 100)) / 100) * factor);
  if (!validos.length || !(sumaPct > 0))
    return { lineas: [], para_inversores: 0, para_desarrolladora: redondear(total, dec) };
  const exactas = validos.map((i) => (paraInversores * i.pct) / sumaPct);
  const partes = exactas.map((x) => Math.floor(x + 1e-9));
  let resto = paraInversores - partes.reduce((a, b) => a + b, 0);
  const orden = exactas.map((x, k) => ({ k, frac: x - Math.floor(x + 1e-9) })).sort((a, b) => b.frac - a.frac);
  for (const { k } of orden) {
    if (resto <= 0) break;
    partes[k] += 1;
    resto -= 1;
  }
  return {
    lineas: validos.map((i, k) => ({ id: i.id, pct: i.pct, monto: partes[k] / factor })),
    para_inversores: paraInversores / factor,
    para_desarrolladora: redondear(total - paraInversores / factor, dec),
  };
}

/** Estado de cuenta del inversor: lo que puso contra lo que recibió (en dinero y en unidades). */
export function estadoCuentaInversor(
  a: {
    aportes: Array<{ tipo: string; monto: number }>;
    distribuciones: Array<{ monto: number; pagado: boolean }>;
    canjes: Array<{ valor: number }>;
  },
  dec: number,
) {
  const sum = (xs: number[]) =>
    redondear(
      xs.reduce((s, x) => s + x, 0),
      dec,
    );
  const porTipo: Record<string, number> = {};
  for (const ap of a.aportes) porTipo[ap.tipo] = redondear((porTipo[ap.tipo] ?? 0) + ap.monto, dec);
  const aportado = sum(a.aportes.map((x) => x.monto));
  const distribuido = sum(a.distribuciones.map((d) => d.monto));
  const pagado = sum(a.distribuciones.filter((d) => d.pagado).map((d) => d.monto));
  const canjes = sum(a.canjes.map((c) => c.valor));
  const recibido = redondear(distribuido + canjes, dec);
  return {
    aportado,
    aportes_por_tipo: porTipo,
    distribuido,
    pagado,
    pendiente_de_pago: redondear(distribuido - pagado, dec),
    canjes,
    recibido,
    saldo: redondear(recibido - aportado, dec),
    // Múltiplo simple sobre lo aportado (sin tiempo): 1,20 = recibió 20 % más de lo que puso.
    multiplo: aportado > 0 ? redondear(recibido / aportado, 4) : null,
  };
}
