import { randomUUID } from "node:crypto";
import { createRequire } from "node:module";
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";

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

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

const requireFromApi = createRequire(new URL("../../apps/api/package.json", import.meta.url));
const Database = requireFromApi("better-sqlite3");
const fixedNow = Date.parse("2026-07-28T09:00:00.000Z");
const roots: string[] = [];
const services: RegistrationService[] = [];

function createHarness() {
  const root = mkdtempSync(join(tmpdir(), "dada-wp1-03-slot-"));
  roots.push(root);
  const databasePath = join(root, "dada.sqlite3");
  const resend = new MockResendAdapter();
  const service = new RegistrationService({
    challengePepper: Buffer.alloc(32, 0x71),
    clock: () => fixedNow,
    codeGenerator: () => "731905",
    currentPrivacyNoticeVersion: "p0a-registration-notice-v1",
    databasePath,
    inviteCodeGenerator: () => `DADA-SLOT-${randomUUID()}`,
    invitePepper: Buffer.alloc(32, 0x72),
    resend,
    sessionPepper: Buffer.alloc(32, 0x73),
  });
  services.push(service);
  return { databasePath, resend, service };
}

function withDatabase<T>(databasePath: string, operation: (database: any) => T): T {
  const database = new Database(databasePath);
  try { return operation(database); } finally { database.close(); }
}

function seedSubject(
  databasePath: string,
  index: number,
  role: "user" | "super_admin",
  status: "active" | "suspended" | "deleted",
) {
  withDatabase(databasePath, (database) => {
    database.prepare(`
      INSERT INTO users (
        user_id, normalized_email, role, status, counts_toward_stage_limit,
        registration_id, created_at
      ) VALUES (?, ?, ?, ?, ?, ?, ?)
    `).run(
      randomUUID(),
      `slot-fixture-${role}-${status}-${index}@example.invalid`,
      role,
      status,
      role === "user" ? 1 : 0,
      randomUUID(),
      fixedNow - 1_000,
    );
  });
}

function writeEvidence(file: string, value: unknown) {
  const directory = process.env.DADA_EVIDENCE_DIR_SLOT;
  if (!directory) return;
  mkdirSync(directory, { recursive: true });
  writeFileSync(resolve(directory, file), `${JSON.stringify(value, null, 2)}\n`);
}

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-WP1-SLOT-001-stage-limit", () => {
  it("counts active and suspended users while excluding deleted users and multiple super_admins", async () => {
    const harness = createHarness();
    for (let index = 0; index < 8; index += 1) seedSubject(harness.databasePath, index, "user", "active");
    seedSubject(harness.databasePath, 8, "user", "suspended");
    seedSubject(harness.databasePath, 9, "user", "deleted");
    seedSubject(harness.databasePath, 10, "super_admin", "active");
    seedSubject(harness.databasePath, 11, "super_admin", "active");

    const invite = harness.service.createInvite({ expiresAt: fixedNow + 86_400_000, maxUses: 3 });
    const tenth = await harness.service.sendRegistrationCode({
      email: "stage-tenth@example.invalid",
      inviteCode: invite.code,
    });
    const completed = harness.service.completeRegistration({
      code: harness.resend.readLatestCode("stage-tenth@example.invalid"),
      creatorName: "Tenth User",
      idempotencyKey: "wp1-03-stage-tenth-complete-00000001",
      privacyConsentAccepted: true,
      privacyNoticeVersion: "p0a-registration-notice-v1",
      registrationId: tenth.registrationId,
      socialId: "@stage_tenth",
    });
    expect(completed.status).toBe("registered");

    await expect(harness.service.sendRegistrationCode({
      email: "stage-eleventh@example.invalid",
      inviteCode: invite.code,
    })).rejects.toMatchObject({ reason: "stage_limit_reached" });

    const counts = withDatabase(harness.databasePath, (database) => ({
      active_and_suspended_users: database.prepare(`
        SELECT COUNT(*) AS count FROM users
        WHERE role = 'user' AND status IN ('active', 'suspended')
      `).get().count,
      deleted_users: database.prepare("SELECT COUNT(*) AS count FROM users WHERE role = 'user' AND status = 'deleted'").get().count,
      super_admins: database.prepare("SELECT COUNT(*) AS count FROM users WHERE role = 'super_admin'").get().count,
    }));
    expect(counts).toEqual({ active_and_suspended_users: 10, deleted_users: 1, super_admins: 2 });
    writeEvidence("response.json", { eleventh: "stage_limit_reached", tenth: completed.status });
    writeEvidence("db-diff.json", { ...counts, failed_invite_use_delta: 0, failed_user_delta: 0 });
  });

  it("rechecks capacity after challenge issuance under BEGIN IMMEDIATE", async () => {
    const harness = createHarness();
    for (let index = 0; index < 9; index += 1) seedSubject(harness.databasePath, index, "user", "active");
    const invite = harness.service.createInvite({ expiresAt: fixedNow + 86_400_000, maxUses: 2 });
    const sent = await harness.service.sendRegistrationCode({
      email: "stage-race@example.invalid",
      inviteCode: invite.code,
    });
    seedSubject(harness.databasePath, 9, "user", "suspended");

    expect(() => harness.service.completeRegistration({
      code: harness.resend.readLatestCode("stage-race@example.invalid"),
      creatorName: "Race User",
      idempotencyKey: "wp1-03-stage-race-complete-000000001",
      privacyConsentAccepted: true,
      privacyNoticeVersion: "p0a-registration-notice-v1",
      registrationId: sent.registrationId,
      socialId: "@stage_race",
    })).toThrowError(expect.objectContaining({ reason: "stage_limit_reached" }));

    const state = withDatabase(harness.databasePath, (database) => ({
      consents: database.prepare("SELECT COUNT(*) AS count FROM privacy_consents").get().count,
      invite_used: database.prepare("SELECT used_count AS count FROM invite_codes WHERE invite_id = ?").get(invite.inviteId).count,
      sessions: database.prepare("SELECT COUNT(*) AS count FROM sessions").get().count,
      users: database.prepare("SELECT COUNT(*) AS count FROM users WHERE role = 'user'").get().count,
    }));
    expect(state).toEqual({ consents: 0, invite_used: 0, sessions: 0, users: 10 });
    writeEvidence("concurrency-trace.json", {
      final_recheck: "stage_limit_reached",
      mode: "BEGIN IMMEDIATE",
      side_effects: state,
    });
  });
});
