import { createKyselyMock } from "@tailor-platform/sdk/vitest";
import { describe, expect, it } from "vitest";
import type { Namespace } from "../generated/kysely-tailordb";
import { activePolicy, draftPolicy, inactivePolicy } from "../testing/fixtures";
import { run } from "./listApprovalPolicies";

describe("listApprovalPolicies", () => {
  it("returns all ACTIVE policies when status = ACTIVE filter is supplied", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([activePolicy]);

    const result = await run(mock.db, { status: "ACTIVE" });

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toEqual([activePolicy]);
      expect(result.value.hasNextPage).toBe(false);
    }
  });

  it("returns only policies matching the supplied purpose", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([draftPolicy, activePolicy, inactivePolicy]);

    const result = await run(mock.db, { purpose: "PRODUCT_ACTIVATION" });

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toHaveLength(3);
      expect(result.value.items.every((p) => p.purpose === "PRODUCT_ACTIVATION")).toBe(true);
    }
  });

  it("returns combinations of purpose and status filters", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([activePolicy]);

    const result = await run(mock.db, {
      purpose: "PRODUCT_ACTIVATION",
      status: "ACTIVE",
    });

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toEqual([activePolicy]);
    }
  });

  it("returns all statuses when status filter is omitted", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([draftPolicy, activePolicy, inactivePolicy]);

    const result = await run(mock.db, {});

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toHaveLength(3);
      const statuses = result.value.items.map((p) => p.status);
      expect(statuses).toEqual(expect.arrayContaining(["DRAFT", "ACTIVE", "INACTIVE"]));
    }
  });

  it("returns all purposes when purpose filter is omitted", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    const otherPurposePolicy = { ...activePolicy, id: "policy-other", purpose: "OTHER" };
    mock.enqueueResults([activePolicy, otherPurposePolicy]);

    const result = await run(mock.db, {});

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toHaveLength(2);
      const purposes = result.value.items.map((p) => p.purpose);
      expect(purposes).toEqual(expect.arrayContaining(["PRODUCT_ACTIVATION", "OTHER"]));
    }
  });

  it("returns an empty array when no policies match", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([]);

    const result = await run(mock.db, { purpose: "NO_MATCH" });

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toEqual([]);
      expect(result.value.hasNextPage).toBe(false);
    }
  });

  it("includes both DRAFT and INACTIVE rows when no implicit hide is applied", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([draftPolicy, inactivePolicy]);

    const result = await run(mock.db, {});

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toHaveLength(2);
      const statuses = result.value.items.map((p) => p.status);
      expect(statuses).toEqual(expect.arrayContaining(["DRAFT", "INACTIVE"]));
    }
  });

  it("orders by (purpose ASC, name ASC, activatedAt DESC) when no orderBy is supplied", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([]);

    await run(mock.db, {});

    expect(mock.selects[0].sql).toMatch(
      /order by .*"purpose" asc, .*"name" asc, .*"activatedAt" desc/i,
    );
  });
});
