import { VacationStatus, VacationType } from "@capakraken/db";
import { RESOURCE_BRIEF_SELECT } from "../db/selects.js";
import { type ResourceHolidayContext } from "../lib/resource-holiday-context.js";
import { VACATION_BALANCE_TYPES } from "../lib/vacation-deduction-snapshot.js";
import { countCalendarDaysInPeriod, countVacationChargeableDays } from "../lib/vacation-day-count.js";
import type { TRPCContext } from "../trpc.js";

type VacationReadDb = TRPCContext["db"];

type VacationPreviewInput = {
  type: VacationType;
  startDate: Date;
  endDate: Date;
  isHalfDay: boolean;
  holidayContext: ResourceHolidayContext;
};

function resolveHolidayDetailSource(
  isoDate: string,
  holidayContext: ResourceHolidayContext,
): "CALENDAR" | "LEGACY_PUBLIC_HOLIDAY" | "CALENDAR_AND_LEGACY" {
  const inCalendar = holidayContext.calendarHolidayStrings.includes(isoDate);
  const inLegacy = holidayContext.publicHolidayStrings.includes(isoDate);

  if (inCalendar && inLegacy) {
    return "CALENDAR_AND_LEGACY";
  }

  return inCalendar ? "CALENDAR" : "LEGACY_PUBLIC_HOLIDAY";
}

export function buildVacationPreview(
  input: VacationPreviewInput,
) {
  const vacation = {
    startDate: input.startDate,
    endDate: input.endDate,
    isHalfDay: input.isHalfDay,
  };
  const requestedDays = countCalendarDaysInPeriod(vacation);
  const effectiveDays = VACATION_BALANCE_TYPES.has(input.type)
    ? countVacationChargeableDays({
        vacation,
        countryCode: input.holidayContext.countryCode,
        federalState: input.holidayContext.federalState,
        metroCityName: input.holidayContext.metroCityName,
        calendarHolidayStrings: input.holidayContext.calendarHolidayStrings,
        publicHolidayStrings: input.holidayContext.publicHolidayStrings,
      })
    : requestedDays;
  const publicHolidayDates = [...new Set([
    ...input.holidayContext.calendarHolidayStrings,
    ...input.holidayContext.publicHolidayStrings,
  ])].sort();

  return {
    requestedDays,
    effectiveDays,
    deductedDays: VACATION_BALANCE_TYPES.has(input.type) ? effectiveDays : 0,
    publicHolidayDates,
    holidayDetails: publicHolidayDates.map((date) => ({
      date,
      source: resolveHolidayDetailSource(date, input.holidayContext),
    })),
    holidayContext: {
      countryCode: input.holidayContext.countryCode ?? null,
      countryName: input.holidayContext.countryName ?? null,
      federalState: input.holidayContext.federalState ?? null,
      metroCityName: input.holidayContext.metroCityName ?? null,
      sources: {
        hasCalendarHolidays: input.holidayContext.calendarHolidayStrings.length > 0,
        hasLegacyPublicHolidayEntries: input.holidayContext.publicHolidayStrings.length > 0,
      },
    },
  };
}

export async function findVacationResourceChapter(
  db: VacationReadDb,
  resourceId: string,
): Promise<string | null> {
  const resource = await db.resource.findUnique({
    where: { id: resourceId },
    select: { chapter: true },
  });

  return resource?.chapter ?? null;
}

export async function listChapterVacationOverlaps(
  db: VacationReadDb,
  input: {
    chapter: string;
    resourceId: string;
    startDate: Date;
    endDate: Date;
  },
) {
  return db.vacation.findMany({
    where: {
      resource: { chapter: input.chapter },
      resourceId: { not: input.resourceId },
      status: { in: [VacationStatus.APPROVED, VacationStatus.PENDING] },
      startDate: { lte: input.endDate },
      endDate: { gte: input.startDate },
    },
    include: {
      resource: { select: RESOURCE_BRIEF_SELECT },
    },
    orderBy: { startDate: "asc" },
    take: 20,
  });
}
