import { describe, expect, test } from "bun:test";
import { readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { findTenancyViolations } from "./tenancy-guard";

describe("findTenancyViolations (unit)", () => {
  test("flags an entry point that queries a per-site table without a gate", () => {
    const v = findTenancyViolations([
      {
        path: "src/app/x/route.ts",
        source: `import { db } from "@/lib/db/client";\nawait db.select().from(keywords);`,
      },
    ]);
    expect(v).toHaveLength(1);
    expect(v[0].tables).toContain("keywords");
  });

  test("passes when an assert helper is present", () => {
    const v = findTenancyViolations([
      {
        path: "src/app/x/route.ts",
        source: `await assertSiteInActiveOrg(siteId);\nawait db.select().from(keywords);`,
      },
    ]);
    expect(v).toHaveLength(0);
  });

  test("passes an org-scoped write via getActiveOrgId", () => {
    const v = findTenancyViolations([
      {
        path: "a.ts",
        source: `"use server";\nconst o = await getActiveOrgId();\nawait db.delete(sites).where(eq(sites.orgId, o));`,
      },
    ]);
    expect(v).toHaveLength(0);
  });

  test("ignores non-entry-point files (internal query modules)", () => {
    const v = findTenancyViolations([
      {
        path: "src/lib/keywords/queries.ts",
        source: `await db.select().from(keywords);`,
      },
    ]);
    expect(v).toHaveLength(0);
  });
});

function collectTsFiles(dir: string, out: string[] = []): string[] {
  for (const e of readdirSync(dir, { withFileTypes: true })) {
    const full = join(dir, e.name);
    if (e.isDirectory()) collectTsFiles(full, out);
    else if (/\.(ts|tsx)$/.test(e.name) && !/\.test\.(ts|tsx)$/.test(e.name))
      out.push(full);
  }
  return out;
}

describe("repo tenancy guard (integration)", () => {
  test("no entry point queries a per-site table without a gate", () => {
    const files = collectTsFiles("src").map((path) => ({
      path,
      source: readFileSync(path, "utf8"),
    }));
    const violations = findTenancyViolations(files);
    const detail = violations
      .map((v) => `  ${v.path} -> ${v.tables.join(", ")}`)
      .join("\n");
    expect(
      violations,
      `Ungated per-site queries found. Add the proper assert helper, or (if it has a valid alternate gate) allowlist it in src/lib/security/tenancy-guard.ts:\n${detail}`,
    ).toHaveLength(0);
  });
});
