import { beforeEach, describe, expect, it, vi } from "vitest";

const { createAuditEntry } = vi.hoisted(() => ({
  createAuditEntry: vi.fn(),
}));

vi.mock("../lib/audit.js", () => ({
  createAuditEntry,
}));

import {
  createHolidayCalendar,
  createHolidayCalendarEntry,
  deleteHolidayCalendarEntry,
  updateHolidayCalendar,
} from "../router/holiday-calendar-procedure-support.js";

function createContext(db: Record<string, unknown>) {
  return {
    db: db as never,
    dbUser: { id: "user_admin" } as never,
  };
}

describe("holiday calendar procedure support", () => {
  beforeEach(() => {
    createAuditEntry.mockReset();
  });

  it("creates a holiday calendar with normalized scope and audit logging", async () => {
    const countryFindUnique = vi.fn().mockResolvedValue({
      id: "country_de",
      name: "Deutschland",
    });
    const metroCityFindUnique = vi.fn().mockResolvedValue(null);
    const holidayCalendarFindFirst = vi.fn().mockResolvedValue(null);
    const holidayCalendarCreate = vi.fn().mockResolvedValue({
      id: "cal_by",
      name: "Bayern Feiertage",
      country: { id: "country_de", code: "DE", name: "Deutschland" },
      metroCity: null,
      entries: [],
    });

    const result = await createHolidayCalendar(
      createContext({
        country: { findUnique: countryFindUnique },
        metroCity: { findUnique: metroCityFindUnique },
        holidayCalendar: {
          findFirst: holidayCalendarFindFirst,
          create: holidayCalendarCreate,
        },
      }),
      {
        name: "Bayern Feiertage",
        scopeType: "STATE",
        countryId: "country_de",
        stateCode: " by ",
      },
    );

    expect(countryFindUnique).toHaveBeenCalledWith({
      where: { id: "country_de" },
      select: { id: true, name: true },
    });
    expect(holidayCalendarFindFirst).toHaveBeenCalledWith({
      where: {
        scopeType: "STATE",
        countryId: "country_de",
        stateCode: "BY",
      },
      select: { id: true },
    });
    expect(holidayCalendarCreate).toHaveBeenCalledWith({
      data: {
        name: "Bayern Feiertage",
        scopeType: "STATE",
        countryId: "country_de",
        stateCode: "BY",
        isActive: true,
        priority: 0,
      },
      include: expect.any(Object),
    });
    expect(result.id).toBe("cal_by");
    expect(createAuditEntry).toHaveBeenCalledWith(
      expect.objectContaining({
        entityType: "HolidayCalendar",
        action: "CREATE",
        entityId: "cal_by",
      }),
    );
  });

  it("updates a holiday calendar with resolved partial scope values", async () => {
    const holidayCalendarFindUnique = vi.fn().mockResolvedValue({
      id: "cal_city",
      name: "Augsburg lokal",
      scopeType: "CITY",
      countryId: "country_de",
      stateCode: null,
      metroCityId: "city_augsburg",
    });
    const holidayCalendarFindFirst = vi.fn().mockResolvedValue(null);
    const metroCityFindUnique = vi.fn().mockResolvedValue({
      id: "city_augsburg",
      countryId: "country_de",
    });
    const holidayCalendarUpdate = vi.fn().mockResolvedValue({
      id: "cal_city",
      name: "Augsburg lokal bevorzugt",
      stateCode: null,
      metroCityId: "city_augsburg",
      country: { id: "country_de", code: "DE", name: "Deutschland" },
      metroCity: { id: "city_augsburg", name: "Augsburg" },
      entries: [],
    });

    const result = await updateHolidayCalendar(
      createContext({
        holidayCalendar: {
          findUnique: holidayCalendarFindUnique,
          findFirst: holidayCalendarFindFirst,
          update: holidayCalendarUpdate,
        },
        metroCity: { findUnique: metroCityFindUnique },
      }),
      {
        id: "cal_city",
        data: {
          name: "Augsburg lokal bevorzugt",
          metroCityId: undefined,
          priority: 7,
        },
      },
    );

    expect(holidayCalendarFindFirst).toHaveBeenCalledWith({
      where: {
        scopeType: "CITY",
        countryId: "country_de",
        metroCityId: "city_augsburg",
        id: { not: "cal_city" },
      },
      select: { id: true },
    });
    expect(holidayCalendarUpdate).toHaveBeenCalledWith({
      where: { id: "cal_city" },
      data: {
        name: "Augsburg lokal bevorzugt",
        priority: 7,
      },
      include: expect.any(Object),
    });
    expect(result.name).toBe("Augsburg lokal bevorzugt");
    expect(createAuditEntry).toHaveBeenCalledWith(
      expect.objectContaining({
        entityType: "HolidayCalendar",
        action: "UPDATE",
        entityId: "cal_city",
      }),
    );
  });

  it("creates and deletes holiday-calendar entries with clamped dates", async () => {
    const holidayCalendarFindUnique = vi.fn().mockResolvedValue({
      id: "cal_de",
      name: "Deutschland",
    });
    const holidayCalendarEntryFindFirst = vi.fn().mockResolvedValue(null);
    const holidayCalendarEntryCreate = vi.fn().mockResolvedValue({
      id: "entry_1",
      holidayCalendarId: "cal_de",
      name: "Neujahr",
      date: new Date("2026-01-01T00:00:00.000Z"),
    });
    const holidayCalendarEntryFindUnique = vi.fn().mockResolvedValue({
      id: "entry_1",
      holidayCalendarId: "cal_de",
      name: "Neujahr",
      date: new Date("2026-01-01T00:00:00.000Z"),
    });
    const holidayCalendarEntryDelete = vi.fn().mockResolvedValue({ id: "entry_1" });

    const created = await createHolidayCalendarEntry(
      createContext({
        holidayCalendar: { findUnique: holidayCalendarFindUnique },
        holidayCalendarEntry: {
          findFirst: holidayCalendarEntryFindFirst,
          create: holidayCalendarEntryCreate,
        },
      }),
      {
        holidayCalendarId: "cal_de",
        name: "Neujahr",
        date: new Date("2026-01-01T14:30:00.000Z"),
      },
    );
    const deleted = await deleteHolidayCalendarEntry(
      createContext({
        holidayCalendarEntry: {
          findUnique: holidayCalendarEntryFindUnique,
          delete: holidayCalendarEntryDelete,
        },
      }),
      { id: "entry_1" },
    );

    expect(holidayCalendarEntryFindFirst).toHaveBeenCalledWith({
      where: {
        holidayCalendarId: "cal_de",
        date: new Date("2026-01-01T00:00:00.000Z"),
      },
      select: { id: true },
    });
    expect(holidayCalendarEntryCreate).toHaveBeenCalledWith({
      data: {
        holidayCalendarId: "cal_de",
        date: new Date("2026-01-01T00:00:00.000Z"),
        name: "Neujahr",
        isRecurringAnnual: false,
      },
    });
    expect(created.id).toBe("entry_1");
    expect(holidayCalendarEntryDelete).toHaveBeenCalledWith({
      where: { id: "entry_1" },
    });
    expect(deleted).toEqual({
      success: true,
      id: "entry_1",
      name: "Neujahr",
    });
    expect(createAuditEntry).toHaveBeenCalledTimes(2);
  });
});
