import { VacationStatus } from "@capakraken/db";
import { TRPCError } from "@trpc/server";
import { describe, expect, it } from "vitest";
import {
  approvableVacationStatuses,
  assertVacationApprovable,
  assertVacationCancelable,
  assertVacationRejectable,
  buildApprovedVacationUpdateData,
  buildRejectedVacationUpdateData,
  buildVacationStatusUpdateData,
  canActorCancelVacation,
  isVacationManagerRole,
} from "../router/vacation-management-support.js";

describe("vacation management support", () => {
  it("exposes approvable statuses and guards invalid transitions", () => {
    expect(approvableVacationStatuses).toEqual([
      VacationStatus.PENDING,
      VacationStatus.CANCELLED,
      VacationStatus.REJECTED,
    ]);

    expect(() => assertVacationApprovable(VacationStatus.PENDING)).not.toThrow();
    expect(() => assertVacationRejectable(VacationStatus.PENDING)).not.toThrow();
    expect(() => assertVacationCancelable(VacationStatus.PENDING)).not.toThrow();

    expect(() => assertVacationApprovable(VacationStatus.APPROVED)).toThrowError(
      new TRPCError({
        code: "BAD_REQUEST",
        message: "Only PENDING, CANCELLED, or REJECTED vacations can be approved",
      }),
    );
    expect(() => assertVacationRejectable(VacationStatus.APPROVED)).toThrowError(
      new TRPCError({
        code: "BAD_REQUEST",
        message: "Only PENDING vacations can be rejected",
      }),
    );
    expect(() => assertVacationCancelable(VacationStatus.CANCELLED)).toThrowError(
      new TRPCError({
        code: "BAD_REQUEST",
        message: "Already cancelled",
      }),
    );
  });

  it("builds approval, rejection, and generic status payloads", () => {
    const approvedAt = new Date("2026-02-01T10:00:00.000Z");

    expect(buildApprovedVacationUpdateData({
      deductionSnapshotWriteData: { deductedDays: 3, deductionSnapshot: { reason: "calendar" } },
      approvedById: "user_mgr",
      approvedAt,
    })).toEqual({
      status: VacationStatus.APPROVED,
      rejectionReason: null,
      deductedDays: 3,
      deductionSnapshot: { reason: "calendar" },
      approvedById: "user_mgr",
      approvedAt,
    });

    expect(buildRejectedVacationUpdateData({
      rejectionReason: "Capacity conflict",
    })).toEqual({
      status: VacationStatus.REJECTED,
      rejectionReason: "Capacity conflict",
    });

    expect(buildVacationStatusUpdateData({
      status: "APPROVED",
      note: "Reviewed",
      approvedById: "user_mgr",
      approvedAt,
    })).toEqual({
      status: "APPROVED",
      approvedById: "user_mgr",
      approvedAt,
      rejectionReason: null,
      note: "Reviewed",
    });

    expect(buildVacationStatusUpdateData({
      status: "CANCELLED",
      approvedById: "user_mgr",
      approvedAt,
    })).toEqual({
      status: "CANCELLED",
    });
  });

  it("captures manager bypass and ownership-based cancellation access", () => {
    expect(isVacationManagerRole("ADMIN")).toBe(true);
    expect(isVacationManagerRole("MANAGER")).toBe(true);
    expect(isVacationManagerRole("USER")).toBe(false);

    expect(canActorCancelVacation({
      actorId: "user_1",
      actorRole: "USER",
      requestedById: "user_1",
      resourceUserId: "user_2",
    })).toBe(true);

    expect(canActorCancelVacation({
      actorId: "user_1",
      actorRole: "USER",
      requestedById: "user_2",
      resourceUserId: "user_1",
    })).toBe(true);

    expect(canActorCancelVacation({
      actorId: "user_mgr",
      actorRole: "MANAGER",
      requestedById: "user_2",
      resourceUserId: null,
    })).toBe(true);

    expect(canActorCancelVacation({
      actorId: "user_1",
      actorRole: "USER",
      requestedById: "user_2",
      resourceUserId: "user_3",
    })).toBe(false);
  });
});
