import { buildSplitAllocationReadModel } from "@capakraken/application";
import { VacationType } from "@capakraken/db";
import { asHolidayResolverDb, getResolvedCalendarHolidays } from "../lib/holiday-availability.js";
import {
  buildTimelineHolidayResourceIds,
  buildTimelineHolidayResourceWhere,
} from "./timeline-holiday-support.js";
import {
  loadTimelineEntriesReadModel,
  TimelineEntriesDbClient,
  TimelineEntriesFilters,
} from "./timeline-read-shared.js";

export async function loadTimelineHolidayOverlays(
  db: TimelineEntriesDbClient,
  input: TimelineEntriesFilters,
) {
  const readModel = await loadTimelineEntriesReadModel(db, input);
  return loadTimelineHolidayOverlaysForReadModel(db, input, readModel);
}

export async function loadTimelineHolidayOverlaysForReadModel(
  db: TimelineEntriesDbClient,
  input: TimelineEntriesFilters,
  readModel: ReturnType<typeof buildSplitAllocationReadModel>,
) {
  const resourceWhere = buildTimelineHolidayResourceWhere({
    chapters: input.chapters,
    eids: input.eids,
    countryCodes: input.countryCodes,
  });
  const matchingResources = resourceWhere
    ? await db.resource.findMany({
        where: resourceWhere,
        select: { id: true },
      })
    : [];
  const resourceIds = buildTimelineHolidayResourceIds({
    assignmentResourceIds: readModel.assignments.map((assignment) => assignment.resourceId),
    requestedResourceIds: input.resourceIds,
    matchingFilterResourceIds: matchingResources.map((resource) => resource.id),
  });

  if (resourceIds.length === 0) {
    return [];
  }

  const resources = await db.resource.findMany({
    where: { id: { in: resourceIds } },
    select: {
      id: true,
      countryId: true,
      federalState: true,
      metroCityId: true,
      country: { select: { code: true, name: true } },
      metroCity: { select: { name: true } },
    },
  });

  const overlays = await Promise.all(
    resources.map(async (resource) => {
      const holidays = await getResolvedCalendarHolidays(asHolidayResolverDb(db), {
        periodStart: input.startDate,
        periodEnd: input.endDate,
        countryId: resource.countryId,
        countryCode: resource.country?.code ?? null,
        federalState: resource.federalState,
        metroCityId: resource.metroCityId,
        metroCityName: resource.metroCity?.name ?? null,
      });

      return holidays.map((holiday) => {
        const holidayDate = new Date(`${holiday.date}T00:00:00.000Z`);
        return {
          id: `calendar-holiday:${resource.id}:${holiday.date}`,
          resourceId: resource.id,
          type: VacationType.PUBLIC_HOLIDAY,
          status: "APPROVED" as const,
          startDate: holidayDate,
          endDate: holidayDate,
          note: holiday.name,
          scope: holiday.scope,
          calendarName: holiday.calendarName,
          sourceType: holiday.sourceType,
          countryCode: resource.country?.code ?? null,
          countryName: resource.country?.name ?? null,
          federalState: resource.federalState ?? null,
          metroCityName: resource.metroCity?.name ?? null,
        };
      });
    }),
  );

  return overlays.flat().sort((left, right) => {
    if (left.resourceId !== right.resourceId) {
      return left.resourceId.localeCompare(right.resourceId);
    }
    return left.startDate.getTime() - right.startDate.getTime();
  });
}
