import { describe, expect, it } from "vitest";
import {
  CreateBlueprintSchema,
  UpdateBlueprintSchema,
  BlueprintFieldDefinitionSchema,
  generateDynamicZodSchema,
} from "../schemas/blueprint.schema.js";
import { CreateOrgUnitSchema, UpdateOrgUnitSchema } from "../schemas/org-unit.schema.js";
import {
  CreateManagementLevelGroupSchema,
  UpdateManagementLevelGroupSchema,
  CreateManagementLevelSchema,
  UpdateManagementLevelSchema,
} from "../schemas/management-level.schema.js";
import {
  CreateUtilizationCategorySchema,
  UpdateUtilizationCategorySchema,
} from "../schemas/utilization-category.schema.js";
import {
  CreateHolidayCalendarSchema,
  UpdateHolidayCalendarSchema,
  CreateHolidayCalendarEntrySchema,
  UpdateHolidayCalendarEntrySchema,
  PreviewResolvedHolidaysSchema,
} from "../schemas/holiday-calendar.schema.js";
import {
  CreateCalculationRuleSchema,
  UpdateCalculationRuleSchema,
} from "../schemas/calculation-rules.schema.js";
import { BlueprintTarget, FieldType } from "../types/enums.js";

// ─── BlueprintFieldDefinitionSchema ─────────────────────────────────────────

describe("BlueprintFieldDefinitionSchema", () => {
  const validField = {
    id: "field-1",
    label: "Project Name",
    key: "project_name",
    type: FieldType.TEXT,
    order: 0,
  };

  it("accepts a minimal valid field definition", () => {
    const result = BlueprintFieldDefinitionSchema.parse(validField);
    expect(result.id).toBe("field-1");
    expect(result.required).toBe(false);
  });

  it("accepts a full field with options and validation", () => {
    const result = BlueprintFieldDefinitionSchema.parse({
      ...validField,
      required: true,
      description: "The name of the project",
      placeholder: "Enter name…",
      defaultValue: "Untitled",
      options: [{ value: "a", label: "Option A", color: "#ff0000" }],
      validation: { minLength: 2, maxLength: 50 },
      group: "General",
    });
    expect(result.required).toBe(true);
    expect(result.options).toHaveLength(1);
    expect(result.validation?.maxLength).toBe(50);
    expect(result.group).toBe("General");
  });

  it("rejects key that does not match snake_case pattern", () => {
    expect(() =>
      BlueprintFieldDefinitionSchema.parse({ ...validField, key: "Project-Name" }),
    ).toThrow();
  });

  it("rejects key starting with a digit", () => {
    expect(() =>
      BlueprintFieldDefinitionSchema.parse({ ...validField, key: "1bad_key" }),
    ).toThrow();
  });

  it("rejects negative order value", () => {
    expect(() => BlueprintFieldDefinitionSchema.parse({ ...validField, order: -1 })).toThrow();
  });

  it("rejects label longer than 200 characters", () => {
    expect(() =>
      BlueprintFieldDefinitionSchema.parse({ ...validField, label: "x".repeat(201) }),
    ).toThrow();
  });
});

// ─── CreateBlueprintSchema ───────────────────────────────────────────────────

describe("CreateBlueprintSchema", () => {
  it("accepts minimal valid input and applies defaults", () => {
    const result = CreateBlueprintSchema.parse({
      name: "Project Template",
      target: BlueprintTarget.PROJECT,
    });
    expect(result.name).toBe("Project Template");
    expect(result.target).toBe("PROJECT");
    expect(result.fieldDefs).toEqual([]);
    expect(result.defaults).toEqual({});
    expect(result.validationRules).toEqual([]);
    expect(result.description).toBeUndefined();
  });

  it("accepts full input with fieldDefs and validationRules", () => {
    const result = CreateBlueprintSchema.parse({
      name: "Resource Blueprint",
      target: BlueprintTarget.RESOURCE,
      description: "Used for all 3D artists",
      fieldDefs: [
        {
          id: "f1",
          label: "Skill Level",
          key: "skill_level",
          type: FieldType.SELECT,
          order: 0,
          options: [
            { value: "junior", label: "Junior" },
            { value: "senior", label: "Senior" },
          ],
        },
      ],
      defaults: { skill_level: "junior" },
      validationRules: [{ field: "skill_level", rule: "required_if", params: { other: "active" } }],
    });
    expect(result.fieldDefs).toHaveLength(1);
    expect(result.defaults.skill_level).toBe("junior");
    expect(result.validationRules[0]?.rule).toBe("required_if");
  });

  it("rejects empty name", () => {
    expect(() =>
      CreateBlueprintSchema.parse({ name: "", target: BlueprintTarget.PROJECT }),
    ).toThrow();
  });

  it("rejects name longer than 200 characters", () => {
    expect(() =>
      CreateBlueprintSchema.parse({ name: "x".repeat(201), target: BlueprintTarget.PROJECT }),
    ).toThrow();
  });

  it("rejects invalid BlueprintTarget enum value", () => {
    expect(() => CreateBlueprintSchema.parse({ name: "Test", target: "TEAM" })).toThrow();
  });
});

// ─── UpdateBlueprintSchema ───────────────────────────────────────────────────

describe("UpdateBlueprintSchema", () => {
  it("accepts an empty object (all fields optional)", () => {
    const result = UpdateBlueprintSchema.parse({});
    expect(result.name).toBeUndefined();
    expect(result.target).toBeUndefined();
  });

  it("accepts a partial update with only name", () => {
    const result = UpdateBlueprintSchema.parse({ name: "Updated Name" });
    expect(result.name).toBe("Updated Name");
    expect(result.fieldDefs).toBeUndefined();
  });

  it("accepts a partial update with only target", () => {
    const result = UpdateBlueprintSchema.parse({ target: BlueprintTarget.RESOURCE });
    expect(result.target).toBe("RESOURCE");
  });

  it("rejects invalid target even in partial update", () => {
    expect(() => UpdateBlueprintSchema.parse({ target: "INVALID" })).toThrow();
  });
});

// ─── generateDynamicZodSchema ────────────────────────────────────────────────

describe("generateDynamicZodSchema", () => {
  it("generates a TEXT field as optional string by default", () => {
    const schema = generateDynamicZodSchema([
      { id: "f1", label: "Title", key: "title", type: FieldType.TEXT, order: 0, required: false },
    ]);
    const result = schema.parse({});
    expect(result.title).toBeUndefined();
    const withValue = schema.parse({ title: "Hello" });
    expect(withValue.title).toBe("Hello");
  });

  it("generates a TEXT field as required when required=true", () => {
    const schema = generateDynamicZodSchema([
      { id: "f1", label: "Title", key: "title", type: FieldType.TEXT, order: 0, required: true },
    ]);
    expect(() => schema.parse({})).toThrow();
    expect(schema.parse({ title: "Hello" }).title).toBe("Hello");
  });

  it("generates a NUMBER field with min/max validation", () => {
    const schema = generateDynamicZodSchema([
      {
        id: "f2",
        label: "Rating",
        key: "rating",
        type: FieldType.NUMBER,
        order: 0,
        required: true,
        validation: { min: 1, max: 10 },
      },
    ]);
    expect(schema.parse({ rating: 5 }).rating).toBe(5);
    expect(() => schema.parse({ rating: 0 })).toThrow();
    expect(() => schema.parse({ rating: 11 })).toThrow();
  });

  it("generates a BOOLEAN field", () => {
    const schema = generateDynamicZodSchema([
      {
        id: "f3",
        label: "Active",
        key: "is_active",
        type: FieldType.BOOLEAN,
        order: 0,
        required: true,
      },
    ]);
    expect(schema.parse({ is_active: true }).is_active).toBe(true);
    expect(schema.parse({ is_active: false }).is_active).toBe(false);
    expect(() => schema.parse({ is_active: "yes" })).toThrow();
  });

  it("generates a DATE field using coerce", () => {
    const schema = generateDynamicZodSchema([
      {
        id: "f4",
        label: "Start Date",
        key: "start_date",
        type: FieldType.DATE,
        order: 0,
        required: true,
      },
    ]);
    const result = schema.parse({ start_date: "2026-01-15" });
    expect(result.start_date).toBeInstanceOf(Date);
  });

  it("generates a SELECT field restricted to defined option values", () => {
    const schema = generateDynamicZodSchema([
      {
        id: "f5",
        label: "Status",
        key: "status",
        type: FieldType.SELECT,
        order: 0,
        required: true,
        options: [
          { value: "draft", label: "Draft" },
          { value: "active", label: "Active" },
        ],
      },
    ]);
    expect(schema.parse({ status: "draft" }).status).toBe("draft");
    expect(() => schema.parse({ status: "unknown" })).toThrow();
  });

  it("generates a MULTI_SELECT field as an array of valid enum values", () => {
    const schema = generateDynamicZodSchema([
      {
        id: "f6",
        label: "Tags",
        key: "tags",
        type: FieldType.MULTI_SELECT,
        order: 0,
        required: true,
        options: [
          { value: "cg", label: "CG" },
          { value: "vfx", label: "VFX" },
        ],
      },
    ]);
    expect(schema.parse({ tags: ["cg", "vfx"] }).tags).toEqual(["cg", "vfx"]);
    expect(() => schema.parse({ tags: ["cg", "invalid"] })).toThrow();
  });

  it("generates an EMAIL field that validates email format", () => {
    const schema = generateDynamicZodSchema([
      { id: "f7", label: "Email", key: "email", type: FieldType.EMAIL, order: 0, required: true },
    ]);
    expect(schema.parse({ email: "user@example.com" }).email).toBe("user@example.com");
    expect(() => schema.parse({ email: "not-an-email" })).toThrow();
  });

  it("generates a URL field that validates URL format", () => {
    const schema = generateDynamicZodSchema([
      { id: "f8", label: "Website", key: "website", type: FieldType.URL, order: 0, required: true },
    ]);
    expect(schema.parse({ website: "https://example.com" }).website).toBe("https://example.com");
    expect(() => schema.parse({ website: "not-a-url" })).toThrow();
  });

  it("generates a TEXT field with minLength/maxLength validation", () => {
    const schema = generateDynamicZodSchema([
      {
        id: "f9",
        label: "Code",
        key: "code",
        type: FieldType.TEXT,
        order: 0,
        required: true,
        validation: { minLength: 3, maxLength: 8 },
      },
    ]);
    expect(schema.parse({ code: "ABC" }).code).toBe("ABC");
    expect(() => schema.parse({ code: "AB" })).toThrow();
    expect(() => schema.parse({ code: "TOOLONGCODE" })).toThrow();
  });

  it("handles a SELECT field with no options as a plain string", () => {
    const schema = generateDynamicZodSchema([
      { id: "f10", label: "Tag", key: "tag", type: FieldType.SELECT, order: 0, required: true },
    ]);
    expect(schema.parse({ tag: "anything" }).tag).toBe("anything");
  });
});

// ─── CreateOrgUnitSchema ─────────────────────────────────────────────────────

describe("CreateOrgUnitSchema", () => {
  it("accepts valid minimal input with defaults", () => {
    const result = CreateOrgUnitSchema.parse({ name: "Studio Munich", level: 5 });
    expect(result.name).toBe("Studio Munich");
    expect(result.level).toBe(5);
    expect(result.sortOrder).toBe(0);
    expect(result.shortName).toBeUndefined();
    expect(result.parentId).toBeUndefined();
  });

  it("accepts full input with all optional fields", () => {
    const result = CreateOrgUnitSchema.parse({
      name: "Department VFX",
      shortName: "VFX",
      level: 6,
      parentId: "parent-1",
      sortOrder: 3,
    });
    expect(result.shortName).toBe("VFX");
    expect(result.parentId).toBe("parent-1");
    expect(result.sortOrder).toBe(3);
  });

  it("rejects level below 5", () => {
    expect(() => CreateOrgUnitSchema.parse({ name: "Test", level: 4 })).toThrow();
  });

  it("rejects level above 7", () => {
    expect(() => CreateOrgUnitSchema.parse({ name: "Test", level: 8 })).toThrow();
  });

  it("rejects shortName longer than 50 characters", () => {
    expect(() =>
      CreateOrgUnitSchema.parse({ name: "Test", level: 5, shortName: "x".repeat(51) }),
    ).toThrow();
  });
});

// ─── UpdateOrgUnitSchema ─────────────────────────────────────────────────────

describe("UpdateOrgUnitSchema", () => {
  it("accepts empty object (all optional)", () => {
    const result = UpdateOrgUnitSchema.parse({});
    expect(result.name).toBeUndefined();
    expect(result.isActive).toBeUndefined();
  });

  it("accepts nullable shortName to clear the field", () => {
    const result = UpdateOrgUnitSchema.parse({ shortName: null });
    expect(result.shortName).toBeNull();
  });

  it("accepts nullable parentId to unset parent", () => {
    const result = UpdateOrgUnitSchema.parse({ parentId: null });
    expect(result.parentId).toBeNull();
  });

  it("accepts isActive flag", () => {
    const result = UpdateOrgUnitSchema.parse({ isActive: false });
    expect(result.isActive).toBe(false);
  });

  it("rejects name longer than 200 characters", () => {
    expect(() => UpdateOrgUnitSchema.parse({ name: "x".repeat(201) })).toThrow();
  });
});

// ─── CreateManagementLevelGroupSchema ───────────────────────────────────────

describe("CreateManagementLevelGroupSchema", () => {
  it("accepts valid input with defaults", () => {
    const result = CreateManagementLevelGroupSchema.parse({
      name: "Senior Management",
      targetPercentage: 0.15,
    });
    expect(result.name).toBe("Senior Management");
    expect(result.targetPercentage).toBe(0.15);
    expect(result.sortOrder).toBe(0);
  });

  it("accepts boundary values for targetPercentage (0 and 1)", () => {
    expect(
      CreateManagementLevelGroupSchema.parse({ name: "A", targetPercentage: 0 }).targetPercentage,
    ).toBe(0);
    expect(
      CreateManagementLevelGroupSchema.parse({ name: "B", targetPercentage: 1 }).targetPercentage,
    ).toBe(1);
  });

  it("rejects targetPercentage above 1", () => {
    expect(() =>
      CreateManagementLevelGroupSchema.parse({ name: "Test", targetPercentage: 1.01 }),
    ).toThrow();
  });

  it("rejects targetPercentage below 0", () => {
    expect(() =>
      CreateManagementLevelGroupSchema.parse({ name: "Test", targetPercentage: -0.01 }),
    ).toThrow();
  });

  it("rejects empty name", () => {
    expect(() =>
      CreateManagementLevelGroupSchema.parse({ name: "", targetPercentage: 0.1 }),
    ).toThrow();
  });
});

// ─── UpdateManagementLevelGroupSchema ───────────────────────────────────────

describe("UpdateManagementLevelGroupSchema", () => {
  it("accepts empty object", () => {
    const result = UpdateManagementLevelGroupSchema.parse({});
    expect(result.name).toBeUndefined();
    expect(result.targetPercentage).toBeUndefined();
  });

  it("accepts partial update with only sortOrder", () => {
    const result = UpdateManagementLevelGroupSchema.parse({ sortOrder: 5 });
    expect(result.sortOrder).toBe(5);
    expect(result.name).toBeUndefined();
  });

  it("rejects targetPercentage out of range in partial update", () => {
    expect(() => UpdateManagementLevelGroupSchema.parse({ targetPercentage: 2 })).toThrow();
  });
});

// ─── CreateManagementLevelSchema ────────────────────────────────────────────

describe("CreateManagementLevelSchema", () => {
  it("accepts valid input", () => {
    const result = CreateManagementLevelSchema.parse({ name: "Director", groupId: "grp-1" });
    expect(result.name).toBe("Director");
    expect(result.groupId).toBe("grp-1");
  });

  it("rejects empty name", () => {
    expect(() => CreateManagementLevelSchema.parse({ name: "", groupId: "grp-1" })).toThrow();
  });

  it("rejects missing groupId", () => {
    expect(() => CreateManagementLevelSchema.parse({ name: "Director" })).toThrow();
  });

  it("rejects name longer than 100 characters", () => {
    expect(() =>
      CreateManagementLevelSchema.parse({ name: "x".repeat(101), groupId: "grp-1" }),
    ).toThrow();
  });
});

// ─── UpdateManagementLevelSchema ────────────────────────────────────────────

describe("UpdateManagementLevelSchema", () => {
  it("accepts empty object", () => {
    const result = UpdateManagementLevelSchema.parse({});
    expect(result.name).toBeUndefined();
    expect(result.groupId).toBeUndefined();
  });

  it("accepts partial update with only groupId", () => {
    const result = UpdateManagementLevelSchema.parse({ groupId: "grp-2" });
    expect(result.groupId).toBe("grp-2");
  });

  it("rejects empty name in partial update", () => {
    expect(() => UpdateManagementLevelSchema.parse({ name: "" })).toThrow();
  });
});

// ─── CreateUtilizationCategorySchema ────────────────────────────────────────

describe("CreateUtilizationCategorySchema", () => {
  it("accepts minimal valid input with defaults", () => {
    const result = CreateUtilizationCategorySchema.parse({ code: "PROD", name: "Production" });
    expect(result.code).toBe("PROD");
    expect(result.name).toBe("Production");
    expect(result.sortOrder).toBe(0);
    expect(result.isDefault).toBe(false);
    expect(result.description).toBeUndefined();
  });

  it("accepts full input including description", () => {
    const result = CreateUtilizationCategorySchema.parse({
      code: "SICK",
      name: "Sick Leave",
      description: "Covers illness absence",
      sortOrder: 2,
      isDefault: true,
    });
    expect(result.isDefault).toBe(true);
    expect(result.description).toBe("Covers illness absence");
  });

  it("rejects code longer than 20 characters", () => {
    expect(() =>
      CreateUtilizationCategorySchema.parse({ code: "x".repeat(21), name: "Test" }),
    ).toThrow();
  });

  it("rejects description longer than 500 characters", () => {
    expect(() =>
      CreateUtilizationCategorySchema.parse({
        code: "ABC",
        name: "Test",
        description: "x".repeat(501),
      }),
    ).toThrow();
  });

  it("rejects empty code", () => {
    expect(() => CreateUtilizationCategorySchema.parse({ code: "", name: "Test" })).toThrow();
  });
});

// ─── UpdateUtilizationCategorySchema ────────────────────────────────────────

describe("UpdateUtilizationCategorySchema", () => {
  it("accepts empty object", () => {
    const result = UpdateUtilizationCategorySchema.parse({});
    expect(result.code).toBeUndefined();
    expect(result.isDefault).toBeUndefined();
  });

  it("accepts nullable description to clear the field", () => {
    const result = UpdateUtilizationCategorySchema.parse({ description: null });
    expect(result.description).toBeNull();
  });

  it("accepts isActive flag", () => {
    const result = UpdateUtilizationCategorySchema.parse({ isActive: false });
    expect(result.isActive).toBe(false);
  });

  it("rejects code longer than 20 characters in partial update", () => {
    expect(() => UpdateUtilizationCategorySchema.parse({ code: "x".repeat(21) })).toThrow();
  });
});

// ─── CreateHolidayCalendarSchema ─────────────────────────────────────────────

describe("CreateHolidayCalendarSchema", () => {
  it("accepts valid COUNTRY-scope calendar", () => {
    const result = CreateHolidayCalendarSchema.parse({
      name: "Germany Public Holidays",
      scopeType: "COUNTRY",
      countryId: "DE",
    });
    expect(result.name).toBe("Germany Public Holidays");
    expect(result.scopeType).toBe("COUNTRY");
    expect(result.stateCode).toBeUndefined();
    expect(result.priority).toBeUndefined();
  });

  it("accepts valid STATE-scope calendar with stateCode", () => {
    const result = CreateHolidayCalendarSchema.parse({
      name: "Bavaria Holidays",
      scopeType: "STATE",
      countryId: "DE",
      stateCode: "BY",
      priority: 10,
      isActive: true,
    });
    expect(result.stateCode).toBe("BY");
    expect(result.priority).toBe(10);
  });

  it("rejects invalid scopeType", () => {
    expect(() =>
      CreateHolidayCalendarSchema.parse({ name: "Test", scopeType: "REGION", countryId: "DE" }),
    ).toThrow();
  });

  it("rejects priority below -100", () => {
    expect(() =>
      CreateHolidayCalendarSchema.parse({
        name: "Test",
        scopeType: "COUNTRY",
        countryId: "DE",
        priority: -101,
      }),
    ).toThrow();
  });

  it("rejects priority above 100", () => {
    expect(() =>
      CreateHolidayCalendarSchema.parse({
        name: "Test",
        scopeType: "COUNTRY",
        countryId: "DE",
        priority: 101,
      }),
    ).toThrow();
  });

  it("rejects stateCode longer than 16 characters", () => {
    expect(() =>
      CreateHolidayCalendarSchema.parse({
        name: "Test",
        scopeType: "STATE",
        countryId: "DE",
        stateCode: "x".repeat(17),
      }),
    ).toThrow();
  });
});

// ─── UpdateHolidayCalendarSchema ─────────────────────────────────────────────

describe("UpdateHolidayCalendarSchema", () => {
  it("accepts empty object", () => {
    const result = UpdateHolidayCalendarSchema.parse({});
    expect(result.name).toBeUndefined();
    expect(result.stateCode).toBeUndefined();
  });

  it("accepts nullable stateCode to clear it", () => {
    const result = UpdateHolidayCalendarSchema.parse({ stateCode: null });
    expect(result.stateCode).toBeNull();
  });

  it("accepts partial update with name and isActive", () => {
    const result = UpdateHolidayCalendarSchema.parse({ name: "Updated Calendar", isActive: false });
    expect(result.name).toBe("Updated Calendar");
    expect(result.isActive).toBe(false);
  });

  it("rejects name longer than 120 characters", () => {
    expect(() => UpdateHolidayCalendarSchema.parse({ name: "x".repeat(121) })).toThrow();
  });
});

// ─── CreateHolidayCalendarEntrySchema ────────────────────────────────────────

describe("CreateHolidayCalendarEntrySchema", () => {
  it("accepts valid entry with date coercion from string", () => {
    const result = CreateHolidayCalendarEntrySchema.parse({
      holidayCalendarId: "cal-1",
      date: "2026-12-25",
      name: "Christmas Day",
    });
    expect(result.holidayCalendarId).toBe("cal-1");
    expect(result.date).toBeInstanceOf(Date);
    expect(result.name).toBe("Christmas Day");
    expect(result.isRecurringAnnual).toBeUndefined();
  });

  it("accepts full entry with all optional fields", () => {
    const result = CreateHolidayCalendarEntrySchema.parse({
      holidayCalendarId: "cal-1",
      date: "2026-10-03",
      name: "German Unity Day",
      isRecurringAnnual: true,
      source: "Official Federal Calendar",
    });
    expect(result.isRecurringAnnual).toBe(true);
    expect(result.source).toBe("Official Federal Calendar");
  });

  it("rejects empty name", () => {
    expect(() =>
      CreateHolidayCalendarEntrySchema.parse({
        holidayCalendarId: "cal-1",
        date: "2026-01-01",
        name: "",
      }),
    ).toThrow();
  });

  it("rejects missing holidayCalendarId", () => {
    expect(() =>
      CreateHolidayCalendarEntrySchema.parse({ date: "2026-01-01", name: "New Year" }),
    ).toThrow();
  });
});

// ─── UpdateHolidayCalendarEntrySchema ────────────────────────────────────────

describe("UpdateHolidayCalendarEntrySchema", () => {
  it("accepts empty object", () => {
    const result = UpdateHolidayCalendarEntrySchema.parse({});
    expect(result.name).toBeUndefined();
    expect(result.date).toBeUndefined();
  });

  it("accepts partial update with date coercion", () => {
    const result = UpdateHolidayCalendarEntrySchema.parse({ date: "2027-01-01" });
    expect(result.date).toBeInstanceOf(Date);
  });

  it("accepts nullable source to clear it", () => {
    const result = UpdateHolidayCalendarEntrySchema.parse({ source: null });
    expect(result.source).toBeNull();
  });
});

// ─── PreviewResolvedHolidaysSchema ───────────────────────────────────────────

describe("PreviewResolvedHolidaysSchema", () => {
  it("accepts valid input with required fields", () => {
    const result = PreviewResolvedHolidaysSchema.parse({ countryId: "DE", year: 2026 });
    expect(result.countryId).toBe("DE");
    expect(result.year).toBe(2026);
    expect(result.stateCode).toBeUndefined();
  });

  it("accepts input with optional stateCode and metroCityId", () => {
    const result = PreviewResolvedHolidaysSchema.parse({
      countryId: "DE",
      stateCode: "BY",
      metroCityId: "city-1",
      year: 2026,
    });
    expect(result.stateCode).toBe("BY");
    expect(result.metroCityId).toBe("city-1");
  });

  it("rejects year below 2000", () => {
    expect(() => PreviewResolvedHolidaysSchema.parse({ countryId: "DE", year: 1999 })).toThrow();
  });

  it("rejects year above 2100", () => {
    expect(() => PreviewResolvedHolidaysSchema.parse({ countryId: "DE", year: 2101 })).toThrow();
  });

  it("rejects non-integer year", () => {
    expect(() => PreviewResolvedHolidaysSchema.parse({ countryId: "DE", year: 2026.5 })).toThrow();
  });
});

// ─── CreateCalculationRuleSchema ─────────────────────────────────────────────

describe("CreateCalculationRuleSchema", () => {
  const validRule = {
    name: "Public Holiday Charge Rule",
    triggerType: "PUBLIC_HOLIDAY",
    costEffect: "CHARGE",
    chargeabilityEffect: "COUNT",
  };

  it("accepts minimal valid input with defaults", () => {
    const result = CreateCalculationRuleSchema.parse(validRule);
    expect(result.name).toBe("Public Holiday Charge Rule");
    expect(result.triggerType).toBe("PUBLIC_HOLIDAY");
    expect(result.costEffect).toBe("CHARGE");
    expect(result.chargeabilityEffect).toBe("COUNT");
    expect(result.priority).toBe(0);
    expect(result.isActive).toBe(true);
    expect(result.description).toBeUndefined();
  });

  it("accepts full input with all optional fields", () => {
    const result = CreateCalculationRuleSchema.parse({
      ...validRule,
      description: "Charges client on public holidays",
      triggerType: "SICK",
      costEffect: "REDUCE",
      costReductionPercent: 50,
      projectId: "proj-1",
      orderType: "CHARGEABLE",
      chargeabilityEffect: "SKIP",
      priority: 100,
      isActive: false,
    });
    expect(result.costReductionPercent).toBe(50);
    expect(result.triggerType).toBe("SICK");
    expect(result.chargeabilityEffect).toBe("SKIP");
    expect(result.isActive).toBe(false);
  });

  it("rejects invalid triggerType", () => {
    expect(() =>
      CreateCalculationRuleSchema.parse({ ...validRule, triggerType: "OVERTIME" }),
    ).toThrow();
  });

  it("rejects costReductionPercent above 100", () => {
    expect(() =>
      CreateCalculationRuleSchema.parse({ ...validRule, costReductionPercent: 101 }),
    ).toThrow();
  });

  it("rejects priority above 1000", () => {
    expect(() => CreateCalculationRuleSchema.parse({ ...validRule, priority: 1001 })).toThrow();
  });

  it("rejects priority below 0", () => {
    expect(() => CreateCalculationRuleSchema.parse({ ...validRule, priority: -1 })).toThrow();
  });
});

// ─── UpdateCalculationRuleSchema ─────────────────────────────────────────────

describe("UpdateCalculationRuleSchema", () => {
  it("accepts minimal input with only required id", () => {
    const result = UpdateCalculationRuleSchema.parse({ id: "rule-1" });
    expect(result.id).toBe("rule-1");
    expect(result.name).toBeUndefined();
    expect(result.triggerType).toBeUndefined();
  });

  it("accepts partial update with name and priority", () => {
    const result = UpdateCalculationRuleSchema.parse({
      id: "rule-1",
      name: "Updated Rule",
      priority: 5,
    });
    expect(result.name).toBe("Updated Rule");
    expect(result.priority).toBe(5);
  });

  it("requires id to be present", () => {
    expect(() => UpdateCalculationRuleSchema.parse({ name: "Some Rule" })).toThrow();
  });

  it("rejects invalid costEffect in partial update", () => {
    expect(() =>
      UpdateCalculationRuleSchema.parse({ id: "rule-1", costEffect: "IGNORE" }),
    ).toThrow();
  });
});
