import test from "node:test";
import assert from "node:assert/strict";
import { once } from "node:events";
import { spawn } from "node:child_process";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

// 他テストとデータファイルを共有しないよう、専用の一時ディレクトリで起動する。
async function startServer() {
  const dir = await mkdtemp(join(tmpdir(), "portal-notif-"));
  const port = 20000 + Math.floor(Math.random() * 20000);
  const child = spawn(process.execPath, ["apps/api/server.mjs"], {
    env: { ...process.env, PORT: String(port), PORTAL_DATA_DIR: dir }, stdio: ["ignore", "pipe", "pipe"],
  });
  await Promise.race([
    once(child.stdout, "data"),
    once(child.stderr, "data").then(([c]) => { throw new Error(c.toString()); }),
  ]);
  return { child, base: `http://127.0.0.1:${port}`, dir };
}

test("申請状況の変化で本人宛の通知が作られ、未読バッジ→既読化できる", async () => {
  const { child, base, dir } = await startServer();
  const H = (token) => ({ "content-type": "application/json", ...(token ? { authorization: `Bearer ${token}` } : {}) });
  try {
    // ログイン
    const login = await (await fetch(`${base}/api/auth/card-login`, { method: "POST", headers: H(), body: JSON.stringify({ cardSerial: "JPKI-0001", pin: "1234" }) })).json();
    const token = login.token;
    assert.ok(token);

    // 申請（証明書オンライン請求）
    const app = await (await fetch(`${base}/api/certificate-requests`, { method: "POST", headers: H(token), body: JSON.stringify({ typeId: "juminhyo", copies: 1, deliveryMethod: "CONVENIENCE" }) })).json();
    assert.ok(app.id);

    // 初期は通知ゼロ（受付時点では通知しない設計）
    let notif = await (await fetch(`${base}/api/notifications`, { headers: H(token) })).json();
    assert.equal(notif.unread, 0);

    // 審査側が状態を進める → 通知が1件（審査中）
    await fetch(`${base}/api/certificate-requests/${app.id}/advance`, { method: "POST", headers: H(token) });
    notif = await (await fetch(`${base}/api/notifications`, { headers: H(token) })).json();
    assert.equal(notif.unread, 1);
    assert.equal(notif.items[0].statusLabel, "審査中");
    assert.equal(notif.items[0].kind, "cert");
    assert.match(notif.items[0].message, /審査/);

    // もう一段進める → 未読2件（交付準備完了が先頭）
    await fetch(`${base}/api/certificate-requests/${app.id}/advance`, { method: "POST", headers: H(token) });
    notif = await (await fetch(`${base}/api/notifications`, { headers: H(token) })).json();
    assert.equal(notif.unread, 2);
    assert.equal(notif.items[0].status, "READY");

    // 既読化 → 未読0
    const read = await (await fetch(`${base}/api/notifications/read`, { method: "POST", headers: H(token) })).json();
    assert.equal(read.marked, 2);
    notif = await (await fetch(`${base}/api/notifications`, { headers: H(token) })).json();
    assert.equal(notif.unread, 0);

    // 未ログインでは 401
    assert.equal((await fetch(`${base}/api/notifications`)).status, 401);
  } finally {
    child.kill();
    await rm(dir, { recursive: true, force: true }).catch(() => {});
  }
});
