import type { QueryContext } from "@tailor-platform/erp-kit/core";
import { createKyselyMock } from "@tailor-platform/sdk/vitest";
import { describe, expect, it } from "vitest";
import type { Namespace } from "../generated/kysely-tailordb";
import {
  baseDeliveredNotification,
  baseFailedNotification,
  baseQueuedNotification,
  baseReadNotification,
  baseSentNotification,
} from "../testing/fixtures";
import { run } from "./getNotification";

describe("getNotification", () => {
  const recipientCtx: QueryContext = {
    actorId: "user-1",
    permissions: [],
  };
  const otherUserCtx: QueryContext = {
    actorId: "user-99",
    permissions: [],
  };

  it("returns the Notification when found by id and caller is the recipient", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    mock.enqueueResults([{ ...baseDeliveredNotification }]);

    const result = await run(mock.db, { id: "notification-3" }, recipientCtx);

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.notification?.id).toBe("notification-3");
      expect(result.value.notification?.recipientUserId).toBe("user-1");
    }
  });

  it("returns the row regardless of deliveryStatus (QUEUED, SENT, DELIVERED, FAILED, BOUNCED)", async () => {
    const statuses = [
      { ...baseQueuedNotification, deliveryStatus: "QUEUED" as const },
      { ...baseSentNotification, deliveryStatus: "SENT" as const },
      { ...baseDeliveredNotification, deliveryStatus: "DELIVERED" as const },
      { ...baseFailedNotification, deliveryStatus: "FAILED" as const },
      { ...baseDeliveredNotification, deliveryStatus: "BOUNCED" as const },
    ];

    for (const row of statuses) {
      const mock = createKyselyMock<Namespace[keyof Namespace]>();
      mock.enqueueResults([row]);

      const result = await run(mock.db, { id: row.id }, recipientCtx);

      expect(result.ok).toBe(true);
      if (result.ok) {
        expect(result.value.notification?.deliveryStatus).toBe(row.deliveryStatus);
      }
    }
  });

  it("returns the row with the current engagementStatuses set", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    mock.enqueueResults([{ ...baseReadNotification }]);

    const result = await run(mock.db, { id: "notification-6" }, recipientCtx);

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.notification?.engagementStatuses).toEqual(["SEEN", "READ"]);
    }
  });

  it("returns null when id does not exist", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    mock.enqueueResults([]);

    const result = await run(mock.db, { id: "nonexistent" }, recipientCtx);

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.notification).toBeNull();
    }
  });

  it("returns null when the caller is not the recipient (no existence oracle)", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    mock.enqueueResults([{ ...baseDeliveredNotification }]);

    const result = await run(mock.db, { id: "notification-3" }, otherUserCtx);

    // Indistinguishable from a missing id: existence is not disclosed.
    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.notification).toBeNull();
    }
  });
});
