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 { ManagedStorage } from "../../apps/api/src/managed-storage.js";
import { RegistrationService } from "../../apps/api/src/registration.js";
import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js";
import { registrationNotice } from "../../packages/shared-contracts/src/registration-notice.js";

const now = Date.parse("2026-07-28T12:00:00.000Z");
const roots: string[] = [];
const services: RegistrationService[] = [];
const storages: ManagedStorage[] = [];
const headers = { host: "127.0.0.1:43121", origin: "http://127.0.0.1:43121" };

async function harness() {
  const root = mkdtempSync(join(tmpdir(), "dada-wp1-05-api-"));
  roots.push(root);
  const databasePath = join(root, "db", "dada.sqlite3");
  const storage = new ManagedStorage({ dataRoot: root, databasePath });
  storages.push(storage);
  const resend = new MockResendAdapter();
  const registration = new RegistrationService({
    challengePepper: Buffer.alloc(32, 0x71), clock: () => now, codeGenerator: () => "539126",
    currentPrivacyNoticeVersion: registrationNotice.version, databasePath,
    inviteCodeGenerator: () => "DADA-WP1-05-API", invitePepper: Buffer.alloc(32, 0x72), resend,
    sessionPepper: Buffer.alloc(32, 0x73),
  });
  services.push(registration);
  const email = "account-api@example.invalid";
  const invite = registration.createInvite({ expiresAt: now + 86_400_000, maxUses: 1 });
  const sent = await registration.sendRegistrationCode({ email, inviteCode: invite.code });
  const completed = registration.completeRegistration({
    code: resend.readLatestCode(email), creatorName: "Account API", idempotencyKey: `register-${randomUUID()}-${randomUUID()}`,
    privacyConsentAccepted: true, privacyNoticeVersion: registrationNotice.version,
    registrationId: sent.registrationId, socialId: "@account_api",
  });
  const app = await createApp({ browserGate: false, networkBoundary: { allowTestPort: true }, registration });
  return { app, completed, email, registration, resend };
}

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

describe("TDD-WP1-DEL-001 account settings and deletion API", () => {
  it("serves safe settings and deletes only after CSRF plus a fresh email code", async () => {
    const { app, completed, email, registration, resend } = await harness();
    const cookie = `dada_session=${completed.sessionToken}`;
    const session = await app.inject({ headers: { ...headers, cookie }, method: "GET", url: "/api/v1/auth/session" });
    const settings = await app.inject({ headers: { ...headers, cookie }, method: "GET", url: "/api/v1/account/settings" });
    expect(settings.statusCode).toBe(200);
    expect(settings.json()).toMatchObject({
      account: { email, status: "active" },
      local_data: { backup_enabled: false, migration_supported: false, location: "configured_local_data_root" },
      profile: { creator_name: "Account API", social_id: "@account_api" },
    });
    expect(JSON.stringify(settings.json())).not.toMatch(/[A-Z]:\\/i);
    const csrf = settings.json().csrf_token;

    const deletionSend = await app.inject({
      headers: { ...headers, cookie, "x-csrf-token": csrf }, method: "POST", url: "/api/v1/account/deletion/send",
    });
    expect(deletionSend.statusCode).toBe(200);
    const code = resend.readLatestCode(email);
    const rejected = await app.inject({
      headers: {
        ...headers, cookie, "idempotency-key": `reject-${randomUUID()}-${randomUUID()}`, "x-csrf-token": csrf,
      },
      method: "POST",
      payload: { confirmation: "注销账号", deletion_id: deletionSend.json().deletion_id, verification_code: "000000" },
      url: "/api/v1/account/deletion/complete",
    });
    expect(rejected.statusCode).toBe(400);
    expect(registration.database.prepare("SELECT failure_count FROM account_deletion_challenges").get().failure_count).toBe(1);
    expect(registration.readUserSession(completed.sessionToken)).toBeDefined();
    const deletion = await app.inject({
      headers: {
        ...headers, cookie, "idempotency-key": `delete-${randomUUID()}-${randomUUID()}`, "x-csrf-token": csrf,
      },
      method: "POST",
      payload: { confirmation: "注销账号", deletion_id: deletionSend.json().deletion_id, verification_code: code },
      url: "/api/v1/account/deletion/complete",
    });
    expect(deletion.statusCode).toBe(200);
    expect(deletion.json()).toEqual({ status: "deleted" });
    expect(deletion.headers["set-cookie"]).toContain("Max-Age=0");
    expect(JSON.stringify(deletion.json())).not.toContain(email);

    const oldSession = await app.inject({ headers: { ...headers, cookie }, method: "GET", url: "/api/v1/auth/session" });
    expect(oldSession.statusCode).toBe(401);
    expect(registration.readUserSession(completed.sessionToken)).toBeUndefined();
    await app.close();
  });
});
