import { describe, expect, it, vi } from "vitest";
import {
  assertHolidayCalendarEntryDateAvailable,
  assertHolidayCalendarScopeConsistency,
  clampHolidayCalendarDate,
  normalizeHolidayCalendarScopeInput,
  normalizeHolidayCalendarStateCode,
  resolveHolidayCalendarUpdateScope,
} from "../router/holiday-calendar-write-support.js";

describe("holiday calendar write support", () => {
  it("normalizes state codes and optional scope fields", () => {
    expect(normalizeHolidayCalendarStateCode(" by ")).toBe("BY");
    expect(normalizeHolidayCalendarStateCode(undefined)).toBeNull();
    expect(normalizeHolidayCalendarScopeInput({
      stateCode: " ny ",
      metroCityId: undefined,
    })).toEqual({
      stateCode: "NY",
      metroCityId: null,
    });
  });

  it("reuses existing scope values for partial updates", () => {
    expect(resolveHolidayCalendarUpdateScope({
      existing: {
        stateCode: "BY",
        metroCityId: "city_1",
      },
      data: {
        stateCode: undefined,
        metroCityId: null,
      },
    })).toEqual({
      stateCode: "BY",
      metroCityId: null,
    });
  });

  it("clamps dates to UTC midnight", () => {
    expect(clampHolidayCalendarDate(new Date("2026-12-24T18:45:00.000Z")).toISOString())
      .toBe("2026-12-24T00:00:00.000Z");
  });

  it("rejects invalid state and city scope combinations before hitting uniqueness checks", async () => {
    const db = {
      metroCity: { findUnique: vi.fn() },
      holidayCalendar: { findFirst: vi.fn() },
    } as never;

    await expect(assertHolidayCalendarScopeConsistency(db, {
      scopeType: "STATE",
      countryId: "country_de",
      stateCode: null,
      metroCityId: null,
    })).rejects.toMatchObject({
      code: "BAD_REQUEST",
      message: "State calendars require a state code",
    });

    await expect(assertHolidayCalendarScopeConsistency(db, {
      scopeType: "CITY",
      countryId: "country_de",
      stateCode: null,
      metroCityId: null,
    })).rejects.toMatchObject({
      code: "BAD_REQUEST",
      message: "City calendars require a metro city",
    });

    expect(db.holidayCalendar.findFirst).not.toHaveBeenCalled();
  });

  it("rejects city scopes whose metro city belongs to a different country", async () => {
    const db = {
      metroCity: {
        findUnique: vi.fn().mockResolvedValue({
          id: "city_augsburg",
          countryId: "country_us",
        }),
      },
      holidayCalendar: { findFirst: vi.fn() },
    } as never;

    await expect(assertHolidayCalendarScopeConsistency(db, {
      scopeType: "CITY",
      countryId: "country_de",
      stateCode: null,
      metroCityId: "city_augsburg",
    })).rejects.toMatchObject({
      code: "BAD_REQUEST",
      message: "Metro city must belong to the selected country",
    });
  });

  it("rejects duplicate holiday entry dates using the clamped date", async () => {
    const db = {
      holidayCalendarEntry: {
        findFirst: vi.fn().mockResolvedValue({ id: "entry_existing" }),
      },
    } as never;

    await expect(assertHolidayCalendarEntryDateAvailable(db, {
      holidayCalendarId: "cal_1",
      date: new Date("2026-12-24T18:45:00.000Z"),
    })).rejects.toMatchObject({
      code: "CONFLICT",
      message: "A holiday entry for this calendar and date already exists",
    });

    expect(db.holidayCalendarEntry.findFirst).toHaveBeenCalledWith({
      where: {
        holidayCalendarId: "cal_1",
        date: new Date("2026-12-24T00:00:00.000Z"),
      },
      select: { id: true },
    });
  });
});
