/**
 * Métricas del dashboard del holding.
 *
 * Dos cosas que el cálculo anterior medía mal:
 *
 * - El churn contaba las suscripciones CREADAS en el mes que hoy están
 *   canceladas, no las DADAS DE BAJA en el mes. Una cuenta vieja que se va este
 *   mes es exactamente el churn del mes, y quedaba afuera.
 * - `fecha_prox_cobro` es un DATE (00:00). Compararlo contra la hora actual daba
 *   por vencido un cobro desde las 00:01 del mismo día en que toca cobrarlo.
 */

export interface SuscripcionParaMetricas {
  estado: unknown;
  created_at?: unknown;
  fecha_cancelacion?: unknown;
}

const aFecha = (v: unknown): Date | null => {
  if (!v) return null;
  const d = new Date(v as string);
  return Number.isNaN(d.getTime()) ? null : d;
};

/** Bajas ocurridas dentro del período, por su fecha de cancelación. */
export function canceladasEnPeriodo(
  suscripciones: SuscripcionParaMetricas[],
  desde: Date,
  hasta: Date,
): number {
  let total = 0;
  for (const s of suscripciones) {
    if (String(s.estado ?? '') !== 'Cancelado') continue;
    // Las bajas históricas quedaron sin fecha: no se pueden atribuir a un mes,
    // así que no se cuentan en lugar de inventarles uno.
    const baja = aFecha(s.fecha_cancelacion);
    if (!baja) continue;
    if (baja >= desde && baja <= hasta) total++;
  }
  return total;
}

/** Porcentaje de bajas sobre la base con la que arrancó el período. */
export function calcularChurn(activasAlCierre: number, canceladas: number): number {
  const base = activasAlCierre + canceladas;
  if (base <= 0) return 0;
  return Math.round((canceladas / base) * 100 * 10) / 10;
}

/** Día calendario como número YYYYMMDD, para comparar sin que moleste la hora. */
const diaCalendario = (d: Date, enUtc: boolean): number =>
  enUtc
    ? d.getUTCFullYear() * 10000 + (d.getUTCMonth() + 1) * 100 + d.getUTCDate()
    : d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();

/**
 * Un cobro está vencido recién cuando pasó su día, no durante el día en que
 * vence.
 *
 * `fecha_prox_cobro` es una columna DATE: Prisma la entrega a medianoche UTC, y
 * este servidor corre en UTC-3, así que el 25/09 llega como 24/09 21:00 local.
 * Compararla contra la hora local daba por vencido el cobro de hoy —y, peor,
 * corría todo un día. Por eso se compara el día calendario: el de la fecha
 * guardada se lee en UTC, el de hoy en la zona del servidor.
 */
export function cobroEstaVencido(fechaProxCobro: unknown, ahora: Date): boolean {
  const fecha = aFecha(fechaProxCobro);
  if (!fecha) return false;
  return diaCalendario(fecha, true) < diaCalendario(ahora, false);
}
