import type { TripStep } from "@/types";

const ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;

function parseLocalDate(value: string): Date | null {
  const match = ISO_DATE.exec(value);
  if (!match) return null;
  const date = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
  return date.getFullYear() === Number(match[1])
    && date.getMonth() === Number(match[2]) - 1
    && date.getDate() === Number(match[3]) ? date : null;
}

export function getTripDayCount(startDate: string, endDate: string): number {
  const start = parseLocalDate(startDate);
  const end = parseLocalDate(endDate);
  if (!start || !end || end < start) return 0;
  return Math.round((end.getTime() - start.getTime()) / 86_400_000) + 1;
}

export function getTripDays(startDate: string, endDate: string): Array<{ day: number; date: string }> {
  const count = getTripDayCount(startDate, endDate);
  return Array.from({ length: count }, (_, index) => {
    const start = parseLocalDate(startDate)!;
    start.setDate(start.getDate() + index);
    const year = start.getFullYear();
    const month = String(start.getMonth() + 1).padStart(2, "0");
    const date = String(start.getDate()).padStart(2, "0");
    return { day: index + 1, date: `${year}-${month}-${date}` };
  });
}

export function isStepDayWithinTrip(day: number, startDate: string, endDate: string): boolean {
  return Number.isInteger(day) && day >= 1 && day <= getTripDayCount(startDate, endDate);
}

export function sortTripSteps(steps: TripStep[]): TripStep[] {
  return [...steps].sort((a, b) => {
    if (a.day !== b.day) return a.day - b.day;
    const aTime = a.startTime || a.time || "99:99";
    const bTime = b.startTime || b.time || "99:99";
    const byTime = aTime.localeCompare(bTime);
    return byTime || a.id.localeCompare(b.id);
  });
}

export function assertStepMutation<T>(row: T | null, action: string): T {
  if (!row) throw new Error(`Étape introuvable ou ${action} non autorisée`);
  return row;
}

export function assertTripCanUseDates(steps: TripStep[], startDate: string, endDate: string): void {
  const count = getTripDayCount(startDate, endDate);
  if (count === 0) throw new Error("La période du voyage est invalide");
  const outside = steps.some((step) => step.day > count);
  if (outside) throw new Error("Impossible de raccourcir le voyage : des étapes existent après la nouvelle date de fin.");
}
