import { randomUUID } from "node:crypto";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";

import { afterEach, describe, expect, it } from "vitest";

import { createApp } from "../../apps/api/src/app.js";
import { RegistrationService } from "../../apps/api/src/registration.js";
import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js";

const roots: string[] = [];
const services: RegistrationService[] = [];
const now = Date.parse("2026-08-04T09:30:00.000Z");
const headers = { host: "127.0.0.1:43121", origin: "http://127.0.0.1:43121" };

function harness() {
  const root = mkdtempSync(join(tmpdir(), "dada-wp6-02-api-"));
  roots.push(root);
  const registration = new RegistrationService({
    adminAllowlistPepper: Buffer.alloc(32, 0xc1),
    challengePepper: Buffer.alloc(32, 0xc2),
    clock: () => now,
    currentPrivacyNoticeVersion: "p0a-private-content-v1",
    databasePath: join(root, "dada.sqlite3"),
    invitePepper: Buffer.alloc(32, 0xc3),
    resend: new MockResendAdapter(),
    sessionPepper: Buffer.alloc(32, 0xc4),
  });
  services.push(registration);
  const adminId = randomUUID();
  const ownerId = randomUUID();
  const projectId = randomUUID();
  const generationId = randomUUID();
  registration.database.prepare(`
    INSERT INTO users (user_id, normalized_email, role, status, counts_toward_stage_limit, registration_id, created_at)
    VALUES (?, ?, 'super_admin', 'active', 0, ?, ?), (?, ?, 'user', 'active', 1, ?, ?)
  `).run(adminId, `admin-${adminId}@example.invalid`, randomUUID(), now, ownerId, `user-${ownerId}@example.invalid`, randomUUID(), now);
  registration.database.prepare("INSERT INTO admin_access (user_id, allowed) VALUES (?, 1)").run(adminId);
  registration.database.prepare("INSERT INTO user_profiles (user_id, creator_name, social_id) VALUES (?, 'Admin', '@admin')").run(adminId);
  registration.database.exec(`
    CREATE TABLE generation_jobs (
      generation_id TEXT PRIMARY KEY, owner_id TEXT NOT NULL, project_id TEXT NOT NULL,
      prompt TEXT NOT NULL, ratio TEXT NOT NULL, status TEXT NOT NULL, model_id TEXT NOT NULL,
      model_config_version INTEGER NOT NULL, confirmed_credit_cost INTEGER NOT NULL,
      reserved_credits INTEGER NOT NULL, final_credit_state TEXT, error_category TEXT,
      created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, submission_ready INTEGER NOT NULL DEFAULT 1
    );
    CREATE TABLE project_images (image_id TEXT PRIMARY KEY, project_id TEXT NOT NULL, generation_id TEXT NOT NULL, created_at INTEGER NOT NULL);
  `);
  registration.database.prepare(`
    INSERT INTO generation_jobs (
      generation_id, owner_id, project_id, prompt, ratio, status, model_id, model_config_version,
      confirmed_credit_cost, reserved_credits, final_credit_state, error_category, created_at, updated_at, submission_ready
    ) VALUES (?, ?, ?, ?, '1:1', 'succeeded', 'demo.model', 1, 2, 0, 'committed', NULL, ?, ?, 1)
  `).run(generationId, ownerId, projectId, "secret prompt must never be listed", now - 1000, now);
  return { registration, adminId, generationId, adminSession: registration.issueAuthenticatedSession(adminId, "admin") };
}

afterEach(() => {
  for (const service of services.splice(0)) service.close();
  for (const root of roots.splice(0)) rmSync(root, { force: true, recursive: true });
});

describe("TDD-WP6-PRIV-001/TDD-WP6-PRIV-002", () => {
  it("persists notice acknowledgement, returns metadata only, and audits every prompt open", async () => {
    const fixture = harness();
    const app = await createApp({ browserGate: false, networkBoundary: { allowTestPort: true }, registration: fixture.registration });
    const cookie = `dada_admin_session=${fixture.adminSession.sessionToken}`;
    const denied = await app.inject({ headers: { ...headers, cookie }, method: "GET", url: "/api/v1/admin/generations" });
    expect(denied.statusCode).toBe(428);
    expect(denied.json()).toMatchObject({ error: { code: "PRIVATE_CONTENT_NOTICE_ACK_REQUIRED", details: { latest_version: "p0a-private-content-v1" } } });
    expect(JSON.stringify(denied.json())).not.toContain("secret prompt");

    const csrf = fixture.registration.issueAdminCsrfToken(fixture.adminSession.sessionToken);
    const ack = await app.inject({
      headers: { ...headers, cookie, "x-csrf-token": csrf, "idempotency-key": "wp6-02-ack-000000000000000000000000000000" },
      method: "POST", payload: { expected_notice_version: "p0a-private-content-v1" }, url: "/api/v1/admin/private-content-notice/ack",
    });
    expect(ack.statusCode).toBe(200);
    expect(ack.json()).toMatchObject({ notice_version: "p0a-private-content-v1", status: "acknowledged" });

    const stale = await app.inject({
      headers: { ...headers, cookie, "x-csrf-token": fixture.registration.issueAdminCsrfToken(fixture.adminSession.sessionToken), "idempotency-key": "wp6-02-ack-stale-000000000000000000000000000" },
      method: "POST", payload: { expected_notice_version: "old-private-content-v0" }, url: "/api/v1/admin/private-content-notice/ack",
    });
    expect(stale.statusCode).toBe(428);
    expect(stale.json()).toMatchObject({ error: { code: "PRIVATE_CONTENT_NOTICE_ACK_REQUIRED", details: { latest_version: "p0a-private-content-v1" } } });

    const list = await app.inject({ headers: { ...headers, cookie }, method: "GET", url: "/api/v1/admin/generations" });
    expect(list.statusCode).toBe(200);
    expect(list.json().items[0]).toMatchObject({ generation_id: fixture.generationId, owner_ref: expect.any(String), status: "succeeded" });
    expect(JSON.stringify(list.json())).not.toContain("secret prompt");

    const opened = await app.inject({ headers: { ...headers, cookie }, method: "GET", url: `/api/v1/admin/private-content/generations/${fixture.generationId}/prompt` });
    expect(opened.statusCode).toBe(200);
    expect(opened.json()).toEqual({ content_type: "prompt", generation_id: fixture.generationId, prompt: "secret prompt must never be listed" });
    expect((fixture.registration.database.prepare("SELECT COUNT(*) AS count FROM private_content_access_logs").get() as { count: number }).count).toBe(1);

    const reopened = await app.inject({ headers: { ...headers, cookie }, method: "GET", url: `/api/v1/admin/private-content/generations/${fixture.generationId}/prompt` });
    expect(reopened.statusCode).toBe(200);
    expect((fixture.registration.database.prepare("SELECT COUNT(*) AS count FROM private_content_access_logs").get() as { count: number }).count).toBe(2);
    await app.close();
  });
});
