import { describe, expect, it } from "vitest";
import { createMockDb, testNotFound } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import { InvalidStatusTransitionError, PolicyNotFoundError } from "../lib/errors.generated";
import { activePolicy, draftPolicy, inactivePolicy } from "../testing/fixtures";
import { run } from "./deactivateApprovalPolicy";

describe("deactivateApprovalPolicy", () => {
  it("deactivates an ACTIVE policy and stamps deactivatedAt", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const deactivatedAt = new Date("2024-04-01T00:00:00.000Z");
    const deactivated = {
      ...activePolicy,
      status: "INACTIVE" as const,
      deactivatedAt,
      updatedAt: deactivatedAt,
    };

    spies.select.mockReturnValue(activePolicy);
    spies.update.mockReturnValue(deactivated);

    const result = await run(db, { id: activePolicy.id });

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.approvalPolicy.status).toBe("INACTIVE");
      expect(result.value.approvalPolicy.deactivatedAt).not.toBeNull();
    }
    expect(spies.set).toHaveBeenCalledWith(
      expect.objectContaining({
        status: "INACTIVE",
        deactivatedAt: expect.any(Date) as unknown as Date,
      }),
    );
  });

  it("throws INVALID_STATUS_TRANSITION when the policy is in DRAFT", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValue(draftPolicy);

    const result = await run(db, { id: draftPolicy.id });

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(InvalidStatusTransitionError);
    }
    expect(spies.update).not.toHaveBeenCalled();
  });

  it("throws INVALID_STATUS_TRANSITION when the policy is already INACTIVE", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValue(inactivePolicy);

    const result = await run(db, { id: inactivePolicy.id });

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(InvalidStatusTransitionError);
    }
    expect(spies.update).not.toHaveBeenCalled();
  });

  it(
    "throws POLICY_NOT_FOUND for a non-existent policyId",
    testNotFound(run, { id: "nonexistent-policy" }, PolicyNotFoundError),
  );
});
