import { TRPCError } from "@trpc/server";
import { describe, expect, it, vi } from "vitest";
import {
  assertCountryCodeAvailable,
  assertMetroCityDeletable,
  buildCountryCreateData,
  buildCountryListWhere,
  buildCountryUpdateData,
  buildMetroCityCreateData,
  buildMetroCityUpdateData,
  findCountryByIdentifier,
  jsonOrNull,
} from "../router/country-support.js";

describe("country support", () => {
  it("builds list filters", () => {
    expect(buildCountryListWhere({ isActive: true })).toEqual({
      isActive: true,
    });
  });

  it("resolves countries by code before fuzzy name fallback", async () => {
    const db = {
      country: {
        findUnique: vi.fn().mockResolvedValue(null),
        findFirst: vi.fn()
          .mockResolvedValueOnce({ id: "country_de", code: "DE" }),
      },
    } as never;

    const result = await findCountryByIdentifier<{ id: string; code: string }>(
      db,
      " de ",
      { select: { id: true, code: true } },
    );

    expect(result).toEqual({ id: "country_de", code: "DE" });
    expect(db.country.findFirst).toHaveBeenNthCalledWith(1, {
      where: { code: { equals: "DE", mode: "insensitive" } },
      select: { id: true, code: true },
    });
  });

  it("rejects duplicate country codes outside the ignored id", async () => {
    const db = {
      country: {
        findUnique: vi.fn().mockResolvedValue({ id: "country_existing", code: "DE" }),
      },
    } as never;

    await expect(assertCountryCodeAvailable(db, "DE")).rejects.toBeInstanceOf(TRPCError);
  });

  it("builds create and sparse update payloads", () => {
    expect(buildCountryCreateData({
      code: "DE",
      name: "Germany",
      dailyWorkingHours: 8,
      scheduleRules: [{ weekday: 1 }],
    })).toEqual({
      code: "DE",
      name: "Germany",
      dailyWorkingHours: 8,
      scheduleRules: [{ weekday: 1 }],
    });

    expect(buildCountryUpdateData({
      dailyWorkingHours: 7.5,
      scheduleRules: null,
      isActive: false,
    })).toEqual({
      dailyWorkingHours: 7.5,
      scheduleRules: expect.anything(),
      isActive: false,
    });

    expect(buildMetroCityCreateData({
      name: "Berlin",
      countryId: "country_de",
    })).toEqual({
      name: "Berlin",
      countryId: "country_de",
    });

    expect(buildMetroCityUpdateData({
      name: "Munich",
    })).toEqual({
      name: "Munich",
    });
  });

  it("maps nullish schedule rules to Prisma.JsonNull", () => {
    expect(jsonOrNull(null)).toBeTypeOf("object");
    expect(jsonOrNull(undefined)).toBeTypeOf("object");
  });

  it("rejects metro-city deletion while resources are assigned", () => {
    expect(() => assertMetroCityDeletable({
      _count: { resources: 1 },
    })).toThrow(TRPCError);
  });
});
