export interface ServicioPenaltyEntry {
  periodo: string;
  servicioId: number;
  servicioNombre: string;
  porcentaje: number;
  color: string | null;
  corresponde: number;
  montoPagado: number;
  fechaPago: string | null;
  fechaVencimiento: string;
  diasMora: number;
  penalidad: number;
}

export interface ServicioPenaltyResult {
  entries: ServicioPenaltyEntry[];
  totalPenalidad: number;
  penalidadDiariaHoy: number;
}

function diasEntreFechas(desde: string, hasta: string): number {
  const d1 = new Date(desde + "T00:00:00");
  const d2 = new Date(hasta + "T00:00:00");
  return Math.max(0, Math.floor((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24)));
}

interface GastoInput {
  servicioId: number;
  periodo: string;
  montoFacturado: number;
  montoPagado: number | null;
  fechaPago: string | null;
}

interface ServicioInput {
  id: number;
  nombre: string;
  porcentaje: number;
  color: string | null;
}

export function calcularPenalidadServicios(
  gastos: GastoInput[],
  servicios: ServicioInput[],
  hoy: string,
  penalDiario: number,
  diaVencimiento: number,
): ServicioPenaltyResult {
  const svcMap = Object.fromEntries(
    servicios.map((s) => [s.id, { nombre: s.nombre, porcentaje: s.porcentaje / 100, color: s.color }]),
  );

  const entries: ServicioPenaltyEntry[] = [];

  for (const g of gastos) {
    const svc = svcMap[g.servicioId];
    if (!svc) continue;

    const corresponde = Math.round(g.montoFacturado * svc.porcentaje * 100) / 100;
    const montoPagado = g.montoPagado ?? 0;

    // Due date: diaVencimiento of the period's month
    const [anio, mes] = g.periodo.split("-").map(Number);
    const ultimoDia = new Date(anio, mes, 0).getDate();
    const diaVenc = Math.min(diaVencimiento, ultimoDia);
    const fechaVencimiento = `${g.periodo}-${String(diaVenc).padStart(2, "0")}`;

    let diasMora = 0;
    let penalidad = 0;

    if (montoPagado >= corresponde) {
      // Fully paid: penalty from vencimiento to payment date
      if (g.fechaPago && g.fechaPago > fechaVencimiento) {
        diasMora = diasEntreFechas(fechaVencimiento, g.fechaPago);
      }
    } else if (hoy > fechaVencimiento) {
      // Partial or unpaid: penalty continues to today
      diasMora = diasEntreFechas(fechaVencimiento, hoy);
    }

    if (diasMora > 0) {
      penalidad = Math.round(corresponde * penalDiario * diasMora);
    }

    entries.push({
      periodo: g.periodo,
      servicioId: g.servicioId,
      servicioNombre: svc.nombre,
      porcentaje: Math.round(svc.porcentaje * 100),
      color: svc.color,
      corresponde,
      montoPagado,
      fechaPago: g.fechaPago,
      fechaVencimiento,
      diasMora,
      penalidad,
    });
  }

  const totalPenalidad = entries.reduce((s, e) => s + e.penalidad, 0);

  const penalidadDiariaHoy = entries.reduce((s, e) => {
    if (e.montoPagado < e.corresponde && e.diasMora > 0) {
      return s + Math.round(e.corresponde * penalDiario);
    }
    return s;
  }, 0);

  return { entries, totalPenalidad, penalidadDiariaHoy };
}
