import { compareSchedulingPriority } from "./compareSchedulingPriority";

export interface ThreeHourSchedulable {
  id: string;
  priorityScore?: number;
  scheduledDate?: string;
  preferredDepartureDate?: string;
  isGovernment?: boolean;
}

export interface ThreeHourBookingBucket<T extends ThreeHourSchedulable = ThreeHourSchedulable> {
  key: string;
  label: string;
  start: Date;
  end: Date;
  bookings: T[];
}

function bucketStart(date: Date): Date {
  const start = new Date(date);
  start.setUTCMinutes(0, 0, 0);
  const hour = start.getUTCHours();
  start.setUTCHours(Math.floor(hour / 3) * 3);
  return start;
}

function formatBucketLabel(start: Date, end: Date): string {
  const dateFmt = new Intl.DateTimeFormat("en-GB", {
    day: "2-digit",
    month: "short",
    year: "numeric",
    timeZone: "UTC",
  });
  const timeFmt = new Intl.DateTimeFormat("en-GB", {
    hour: "2-digit",
    minute: "2-digit",
    hour12: false,
    timeZone: "UTC",
  });
  return `${dateFmt.format(start)} · ${timeFmt.format(start)} – ${timeFmt.format(end)} UTC`;
}

function getScheduledDate(booking: ThreeHourSchedulable): Date {
  const raw = booking.scheduledDate ?? booking.preferredDepartureDate;
  if (!raw) return new Date(0);
  return new Date(raw);
}

function toPriorityRow(booking: ThreeHourSchedulable) {
  return {
    isGovernment: booking.isGovernment,
    priorityScore: booking.priorityScore,
    scheduledDate: booking.scheduledDate ?? booking.preferredDepartureDate ?? "",
  };
}

export function groupBookingsByThreeHourWindow<T extends ThreeHourSchedulable>(
  bookings: T[],
): ThreeHourBookingBucket<T>[] {
  const map = new Map<string, ThreeHourBookingBucket<T>>();

  for (const booking of bookings) {
    const scheduled = getScheduledDate(booking);
    const start = bucketStart(scheduled);
    const end = new Date(start);
    end.setUTCHours(end.getUTCHours() + 3);
    const key = start.toISOString();

    const existing = map.get(key);
    if (existing) {
      existing.bookings.push(booking);
    } else {
      map.set(key, {
        key,
        label: formatBucketLabel(start, end),
        start,
        end,
        bookings: [booking],
      });
    }
  }

  return [...map.values()]
    .map((bucket) => ({
      ...bucket,
      bookings: [...bucket.bookings].sort((a, b) =>
        compareSchedulingPriority(toPriorityRow(a), toPriorityRow(b)),
      ),
    }))
    .sort((a, b) => a.start.getTime() - b.start.getTime());
}
