// src/lib/sites/assert-entities.test.ts — guards keyword/content-item → org active.
// Integration, gated on DB_TESTS=1. The REAL guards run (no assert-site mock);
// only the session primitive is stubbed (active org = demo-org).
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
import { __clearTestCaller, __setTestCaller } from "./access";

// server-only throws outside Next.js; stub it for the test runner.
mock.module("server-only", () => ({}));
// The guards resolve the org from the session — stub the primitive only.
mock.module("@/lib/active-org", () => ({
  getActiveOrgId: async () => "demo-org",
  getActiveUserId: async () => "seed-owner",
}));

const RUN_DB = process.env.DB_TESTS === "1";

describe.skipIf(!RUN_DB)(
  "assertKeyword/ContentItemInActiveOrg (postgres)",
  () => {
    let db: typeof import("@/lib/db/client").db;
    let schema: typeof import("@/lib/db/domain-schema");
    const ORG = "demo-org"; // matches getActiveOrgId() stub (seeded by db:seed)
    const OTHER_ORG = "wt-ae-other-org";
    const SITE = "wt-ae-site";
    const OTHER_SITE = "wt-ae-site-other";

    beforeEach(async () => {
      __setTestCaller({ userId: "seed-owner", orgId: ORG, role: "owner" });
      ({ db } = await import("@/lib/db/client"));
      schema = await import("@/lib/db/domain-schema");
      const { organization } = await import("@/lib/db/auth-schema");
      const { assertTestDb } = await import("@/lib/db/assert-test-db");
      const { eq, inArray } = await import("drizzle-orm");
      await assertTestDb();
      // sites cascade-deletes keywords + content items.
      await db
        .delete(schema.sites)
        .where(inArray(schema.sites.id, [SITE, OTHER_SITE]));
      await db.delete(organization).where(eq(organization.id, OTHER_ORG));
      await db.insert(organization).values({
        id: OTHER_ORG,
        name: "Other Org",
        slug: `wt-ae-${Date.now()}`,
        createdAt: new Date(),
      });
      await db.insert(schema.sites).values([
        {
          id: SITE,
          orgId: ORG,
          ownerUserId: "seed-owner",
          name: "WT AE Site",
          url: "https://wt-ae-site.com",
          primaryLanguage: "fr",
          languages: [],
          targetCountries: ["FR"],
        },
        {
          id: OTHER_SITE,
          orgId: OTHER_ORG,
          ownerUserId: "seed-owner",
          name: "WT AE Other Site",
          url: "https://wt-ae-site-other.com",
          primaryLanguage: "fr",
          languages: [],
          targetCountries: ["FR"],
        },
      ]);
      await db.insert(schema.keywords).values([
        {
          id: "wt-ae-kw",
          siteId: SITE,
          term: "garde tenancy",
          status: "idea",
          primarySource: "manual",
        },
        {
          id: "wt-ae-kw-other",
          siteId: OTHER_SITE,
          term: "garde tenancy autre org",
          status: "idea",
          primarySource: "manual",
        },
      ]);
      await db.insert(schema.contentItems).values([
        { id: "wt-ae-ci", siteId: SITE, title: "Item in org" },
        { id: "wt-ae-ci-other", siteId: OTHER_SITE, title: "Item other org" },
      ]);
    });

    afterEach(() => __clearTestCaller());

    test("assertKeywordInActiveOrg passe et retourne le siteId pour un mot-clé de l'org", async () => {
      const { assertKeywordInActiveOrg } = await import("./assert-site");
      expect(await assertKeywordInActiveOrg("wt-ae-kw")).toBe(SITE);
    });

    test("assertKeywordInActiveOrg jette pour un mot-clé d'une autre org (tenancy)", async () => {
      const { assertKeywordInActiveOrg } = await import("./assert-site");
      await expect(assertKeywordInActiveOrg("wt-ae-kw-other")).rejects.toThrow(
        "does not belong to the active organization",
      );
    });

    test("assertKeywordInActiveOrg jette pour un id inconnu (fail-closed)", async () => {
      const { assertKeywordInActiveOrg } = await import("./assert-site");
      await expect(assertKeywordInActiveOrg("wt-ae-ghost")).rejects.toThrow(
        "Keyword does not belong to the active organization",
      );
    });

    test("assertContentItemInActiveOrg passe et retourne le siteId pour un item de l'org", async () => {
      const { assertContentItemInActiveOrg } = await import("./assert-site");
      expect(await assertContentItemInActiveOrg("wt-ae-ci")).toBe(SITE);
    });

    test("assertContentItemInActiveOrg jette pour un item d'une autre org (tenancy)", async () => {
      const { assertContentItemInActiveOrg } = await import("./assert-site");
      await expect(
        assertContentItemInActiveOrg("wt-ae-ci-other"),
      ).rejects.toThrow("does not belong to the active organization");
    });

    test("assertContentItemInActiveOrg jette pour un id inconnu (fail-closed)", async () => {
      const { assertContentItemInActiveOrg } = await import("./assert-site");
      await expect(assertContentItemInActiveOrg("wt-ae-ghost")).rejects.toThrow(
        "Content item does not belong to the active organization",
      );
    });
  },
);
