import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { join, dirname } from "node:path";
import { vi } from "vitest";
import type { SanitizedConfig } from "payload";
import { PayloadDataExport } from "@/payload-data-export";
import { RecordingAuditLog } from "@repo/core-testing/instrumentation";

const __dir = dirname(fileURLToPath(import.meta.url));
const contextFilePath = join(__dir, "../../src/contexts/user-data.jsonld");

function loadContextFile(): Record<string, unknown> {
  const raw = JSON.parse(readFileSync(contextFilePath, "utf-8")) as {
    "@context": Record<string, unknown>;
  };
  return raw["@context"];
}

describe("user-data.jsonld context", () => {
  it("is valid JSON with an @context key", () => {
    const raw = JSON.parse(readFileSync(contextFilePath, "utf-8")) as unknown;
    expect(raw).toMatchObject({ "@context": expect.any(Object) });
  });

  it("declares @vocab pointing to schema.org", () => {
    const ctx = loadContextFile();
    expect(ctx["@vocab"]).toBe("https://schema.org/");
  });

  it("declares dsr namespace pointing to DPV", () => {
    const ctx = loadContextFile();
    expect(ctx["dsr"]).toBe("https://w3.org/ns/dpv#");
  });

  it("declares prov namespace", () => {
    const ctx = loadContextFile();
    expect(ctx["prov"]).toBe("https://www.w3.org/ns/prov#");
  });

  it("maps subjectId to schema.org identifier", () => {
    const ctx = loadContextFile();
    expect(ctx["subjectId"]).toBe("identifier");
  });

  it("maps exportedAt to schema.org dateCreated", () => {
    const ctx = loadContextFile();
    expect(ctx["exportedAt"]).toBe("dateCreated");
  });

  it("maps data as an @index container", () => {
    const ctx = loadContextFile();
    expect(ctx["data"]).toMatchObject({ "@container": "@index" });
  });

  it("maps asSelf to a DSR handling type", () => {
    const ctx = loadContextFile();
    expect(ctx["asSelf"]).toMatchObject({ "@type": "@id" });
  });

  it("maps asReference to a data subject right type", () => {
    const ctx = loadContextFile();
    expect(ctx["asReference"]).toMatchObject({ "@type": "@id" });
  });

  it("json-ld bundle includes the inline context matching the file", async () => {
    const auditLog = new RecordingAuditLog();
    const mockPayload = { find: vi.fn().mockResolvedValue({ docs: [] }) };
    const mockGetPayload = vi.fn().mockResolvedValue(mockPayload);
    const config = { collections: [] } as unknown as SanitizedConfig;

    const exporter = new PayloadDataExport(config, auditLog, mockGetPayload);
    const bundle = await exporter.exportSubjectData("alice", "json-ld");

    const fileCtx = loadContextFile();
    const bundleCtx = bundle["@context"] as Record<string, unknown>;

    // Core keys must match between the file and the inline constant
    expect(bundleCtx["@vocab"]).toBe(fileCtx["@vocab"]);
    expect(bundleCtx["dsr"]).toBe(fileCtx["dsr"]);
    expect(bundleCtx["subjectId"]).toBe(fileCtx["subjectId"]);
    expect(bundleCtx["exportedAt"]).toBe(fileCtx["exportedAt"]);
  });
});
