/**
 * Unit-aware interval math (issue #59) for the frontend's progress bars and
 * calendar projection stepping. Uses an AVERAGE day-span per unit (below), an
 * intentional approximation — the backend `helpers/dates.add_interval` is
 * calendar-exact (Jan+1mo = 31 days), so display-side spans can differ by a day
 * or two. Cosmetic only. Pure functions — unit-tested in interval.test.ts.
 */

/** Approximate (average) days per interval unit — mean Gregorian month / Julian
 *  year. NOT calendar-exact; see the module note above. */
export const UNIT_DAYS: Record<string, number> = {
  days: 1,
  weeks: 7,
  months: 30.4368,
  years: 365.25,
};

/** Approximate length of `intervalDays` of `unit` in days; 0 when no interval. */
export function intervalSpanDays(
  intervalDays: number | null | undefined,
  unit?: string | null,
): number {
  if (!intervalDays || intervalDays <= 0) return 0;
  return intervalDays * (UNIT_DAYS[unit || "days"] ?? 1);
}

/**
 * Progress through the current cycle, unit-aware.
 * Returns a clamped 0–100 % plus `overflow` (raw % > 100, i.e. past due).
 * Falls back to {0, false} when there is no usable interval/countdown.
 */
export function daysProgress(
  intervalDays: number | null | undefined,
  daysUntilDue: number | null | undefined,
  unit?: string | null,
): { pct: number; overflow: boolean } {
  const span = intervalSpanDays(intervalDays, unit);
  if (span <= 0 || daysUntilDue == null) return { pct: 0, overflow: false };
  const raw = ((span - daysUntilDue) / span) * 100;
  return { pct: Math.max(0, Math.min(100, raw)), overflow: raw > 100 };
}
