import { TRPCError } from "@trpc/server"; import { findUniqueOrThrow } from "../db/helpers.js"; import { type HolidayCalendarDb, } from "./holiday-calendar-shared.js"; import type { HolidayCalendarScopeInput } from "@capakraken/shared"; type HolidayCalendarScope = HolidayCalendarScopeInput; const HOLIDAY_SCOPE = { COUNTRY: "COUNTRY", STATE: "STATE", CITY: "CITY", } as const satisfies Record; export function clampHolidayCalendarDate(date: Date): Date { const value = new Date(date); value.setUTCHours(0, 0, 0, 0); return value; } export function normalizeHolidayCalendarStateCode( stateCode: string | null | undefined, ): string | null { return stateCode?.trim().toUpperCase() ?? null; } export function normalizeHolidayCalendarScopeInput(input: { stateCode?: string | null | undefined; metroCityId?: string | null | undefined; }) { return { stateCode: normalizeHolidayCalendarStateCode(input.stateCode), metroCityId: input.metroCityId ?? null, }; } export function resolveHolidayCalendarUpdateScope(input: { existing: { stateCode: string | null; metroCityId: string | null; }; data: { stateCode?: string | null | undefined; metroCityId?: string | null | undefined; }; }) { return { stateCode: input.data.stateCode === undefined ? input.existing.stateCode : normalizeHolidayCalendarStateCode(input.data.stateCode), metroCityId: input.data.metroCityId === undefined ? input.existing.metroCityId : input.data.metroCityId ?? null, }; } export async function assertHolidayCalendarEntryDateAvailable( db: HolidayCalendarDb, input: { holidayCalendarId: string; date: Date; }, ignoreId?: string, ) { const existing = await db.holidayCalendarEntry.findFirst({ where: { holidayCalendarId: input.holidayCalendarId, date: clampHolidayCalendarDate(input.date), ...(ignoreId ? { id: { not: ignoreId } } : {}), }, select: { id: true }, }); if (existing) { throw new TRPCError({ code: "CONFLICT", message: "A holiday entry for this calendar and date already exists", }); } } export async function assertHolidayCalendarScopeConsistency( db: HolidayCalendarDb, input: { scopeType: HolidayCalendarScope; countryId: string; stateCode?: string | null; metroCityId?: string | null; }, ignoreId?: string, ) { if (input.scopeType === HOLIDAY_SCOPE.COUNTRY) { if (input.stateCode || input.metroCityId) { throw new TRPCError({ code: "BAD_REQUEST", message: "Country calendars may not define a state or metro city", }); } } if (input.scopeType === HOLIDAY_SCOPE.STATE) { if (!input.stateCode) { throw new TRPCError({ code: "BAD_REQUEST", message: "State calendars require a state code", }); } if (input.metroCityId) { throw new TRPCError({ code: "BAD_REQUEST", message: "State calendars may not define a metro city", }); } } if (input.scopeType === HOLIDAY_SCOPE.CITY) { if (!input.metroCityId) { throw new TRPCError({ code: "BAD_REQUEST", message: "City calendars require a metro city", }); } const metroCity = await findUniqueOrThrow( db.metroCity.findUnique({ where: { id: input.metroCityId }, select: { id: true, countryId: true }, }), "Metro city", ); if (metroCity.countryId !== input.countryId) { throw new TRPCError({ code: "BAD_REQUEST", message: "Metro city must belong to the selected country", }); } } const existing = await db.holidayCalendar.findFirst({ where: { countryId: input.countryId, scopeType: input.scopeType, ...(input.scopeType === HOLIDAY_SCOPE.STATE ? { stateCode: input.stateCode ?? null } : {}), ...(input.scopeType === HOLIDAY_SCOPE.CITY ? { metroCityId: input.metroCityId ?? null } : {}), ...(ignoreId ? { id: { not: ignoreId } } : {}), }, select: { id: true }, }); if (existing) { throw new TRPCError({ code: "CONFLICT", message: "A holiday calendar for this exact scope already exists", }); } }