import { createKyselyMock } from "@tailor-platform/sdk/vitest";
import { describe, expect, it } from "vitest";
import { testNotFound } from "../../../testing";
import type { Namespace } 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 mock = createKyselyMock<Namespace["main-db"]>();
    const deactivatedAt = new Date("2024-04-01T00:00:00.000Z");
    const deactivated = {
      ...activePolicy,
      status: "INACTIVE" as const,
      deactivatedAt,
      updatedAt: deactivatedAt,
    };

    mock.enqueueResults([activePolicy], [deactivated]);

    const result = await mock.withTx((trx) => run(trx, { 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(mock.updates[0].updateValues()).toEqual(
      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 mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([draftPolicy]);

    const result = await mock.withTx((trx) => run(trx, { id: draftPolicy.id }));

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(InvalidStatusTransitionError);
    }
    expect(mock.updates).toHaveLength(0);
  });

  it("throws INVALID_STATUS_TRANSITION when the policy is already INACTIVE", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([inactivePolicy]);

    const result = await mock.withTx((trx) => run(trx, { id: inactivePolicy.id }));

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(InvalidStatusTransitionError);
    }
    expect(mock.updates).toHaveLength(0);
  });

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