// Integration test — gated on DB_TESTS=1, run against the *_test DB only.
import { beforeEach, describe, expect, mock, test } from "bun:test";
import { eq } from "drizzle-orm";

// actions/queries import "server-only" (throws outside Next) — stub it.
mock.module("server-only", () => ({}));
// next/cache primitives throw outside a Next request scope — stub them.
mock.module("next/cache", () => ({
  revalidatePath: () => {},
  revalidateTag: () => {},
  updateTag: () => {},
  unstable_cache:
    (fn: (...args: unknown[]) => unknown) =>
    (...args: unknown[]) =>
      fn(...args),
}));

// `importBriefByTerm`'s org guard resolves the active org's visible sites via
// getSitesForActiveOrg (needs a session/headers()). Stub it to a fixed set so we
// can exercise the membership check deterministically: SITE_A is visible, SITE_B
// is not.
mock.module("@/lib/sites/access", () => ({
  getSitesForActiveOrg: async () => [{ id: "lustre-lab" }],
}));
// The reused attach core (importKeywordBriefAction) re-asserts tenancy via
// assert-site (needs a session). Stub it pass-through; site-scoping of the write
// is covered at the SQL level here and in assert-site.test.ts.
mock.module("@/lib/sites/assert-site", () => ({
  siteBelongsToOrg: async () => true,
  assertSiteInActiveOrg: async () => {},
  assertKeywordInActiveOrg: async () => "mock-site",
  assertContentItemInActiveOrg: async () => "mock-site",
}));

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

// A real Lumenia/YTG brief: query "jewelry 3d printing" → slug "jewelry-3d-printing",
// English (USA) → country "US".
const BRIEF_TXT = [
  "Lumenia.io SEO Brief",
  "Query: jewelry 3d printing",
  "Language: English (USA)",
  "Year: 2026",
  "",
  "=======================",
  "Context and Objective",
  "=======================",
  "Primary Intent: Informational",
  "Objective:",
  "  - Educate readers about 3D printing",
  "",
  "---",
  "Generated by Lumenia.io © 2026",
].join("\n");

const GUIDE_TXT = [
  "Lumenia.io SEO GUIDE",
  "Query        : jewelry 3d printing",
  "Language     : English (USA)",
  "",
  "== TOP TERMS ==",
  "1. jewelrymaking",
  "2. jewelry",
].join("\n");

describe.skipIf(!RUN_DB)("importBriefByTerm (postgres)", () => {
  let db: typeof import("@/lib/db/client").db;
  let schema: typeof import("@/lib/db/domain-schema");
  let actions: typeof import("./brief-by-term-actions");

  const SITE_A = "lustre-lab"; // visible to the active org (stub)
  const SITE_B = "atelier-forge"; // NOT visible

  beforeEach(async () => {
    ({ db } = await import("@/lib/db/client"));
    schema = await import("@/lib/db/domain-schema");
    actions = await import("./brief-by-term-actions");
    const { assertTestDb } = await import("@/lib/db/assert-test-db");
    await assertTestDb();
    await db.delete(schema.keywords);
    await db.delete(schema.sites);
    await db.insert(schema.sites).values([
      {
        id: SITE_A,
        orgId: "demo-org",
        ownerUserId: "seed-owner",
        name: "Lustre Lab",
        url: "https://lustrelab.com",
        primaryLanguage: "en",
        languages: [],
        targetCountries: ["US"],
      },
      {
        id: SITE_B,
        orgId: "other-org",
        ownerUserId: "seed-owner",
        name: "Atelier Forge",
        url: "https://atelierforge.com",
        primaryLanguage: "en",
        languages: [],
        targetCountries: ["US"],
      },
    ]);
  });

  test("match: attaches the brief and returns matched:true with the keyword id", async () => {
    // Seed a keyword whose term slugifies to the brief's query.
    await db.insert(schema.keywords).values({
      id: `${SITE_A}-jewelry-3d-printing`,
      siteId: SITE_A,
      term: "jewelry 3d printing",
      lang: "en",
      country: "US",
      status: "idea",
      intent: ["informational"],
      primarySource: "manual",
      sources: ["manual"],
      metrics: {},
      trend: [],
      briefs: {},
    });

    const res = await actions.importBriefByTerm(SITE_A, BRIEF_TXT, GUIDE_TXT);

    expect(res.matched).toBe(true);
    expect(res.keywordId).toBe(`${SITE_A}-jewelry-3d-printing`);
    expect(res.term).toBe("jewelry 3d printing");

    // The brief is now persisted under the keyword's country (US).
    const [row] = await db
      .select({ briefs: schema.keywords.briefs })
      .from(schema.keywords)
      .where(eq(schema.keywords.id, `${SITE_A}-jewelry-3d-printing`));
    expect(row?.briefs?.US).toBeTruthy();
    expect(row?.briefs?.US?.query).toBe("jewelry 3d printing");
    expect(row?.briefs?.US?.country).toBe("US");
  });

  test("no match: returns matched:false and writes nothing", async () => {
    // No keyword for this term on the site.
    const res = await actions.importBriefByTerm(SITE_A, BRIEF_TXT, GUIDE_TXT);

    expect(res.matched).toBe(false);
    expect(res.keywordId).toBeUndefined();
    expect(res.term).toBe("jewelry 3d printing");

    const rows = await db.select().from(schema.keywords);
    expect(rows).toHaveLength(0);
  });

  test("org isolation: a siteId from another org throws", async () => {
    await expect(
      actions.importBriefByTerm(SITE_B, BRIEF_TXT, GUIDE_TXT),
    ).rejects.toThrow();
  });
});
