// マイナンバーカード認証（JPKI 公的個人認証のシミュレーション）
//
// 実機では IC カードリーダ/スマホ NFC でマイナンバーカードの
// 「利用者証明用電子証明書」を読み取り、利用者証明用パスワード(4桁)で
// 本人を確認する。本リファレンス実装ではその検証をシミュレートし、
// 検証成功時に署名付きセッショントークンを発行する。
import crypto from "node:crypto";

const SECRET = process.env.PORTAL_SECRET || "citizen-portal-dev-secret";
const SESSION_TTL_MS = 30 * 60 * 1000; // 30分

// 公的個人認証の模擬データ（実機では券面/証明書から取得する基本4情報＋宛名番号）
// cardSerial = 利用者証明用電子証明書のシリアル番号（模擬）
export const MOCK_CITIZENS = [
  {
    cardSerial: "JPKI-0001",
    pin: "1234", // 利用者証明用パスワード(4桁数字) ※模擬
    residentId: "1000000001",
    familyNameKanji: "山田", givenNameKanji: "花子",
    familyNameKana: "ヤマダ", givenNameKana: "ハナコ",
    birthDate: "1990-04-01", sex: "F",
    addressText: "サンプル市中央区1-2-3",
  },
  {
    cardSerial: "JPKI-0002",
    pin: "5678",
    residentId: "1000000002",
    familyNameKanji: "鈴木", givenNameKanji: "一郎",
    familyNameKana: "スズキ", givenNameKana: "イチロウ",
    birthDate: "1982-11-20", sex: "M",
    addressText: "サンプル市港区4-5-6",
  },
];

// PIN 連続誤りロック（実機のカードロック相当）
const lockState = new Map(); // cardSerial -> { fails, lockedUntil }
const MAX_PIN_FAILS = 3;
const LOCK_MS = 5 * 60 * 1000;

const sessions = new Map(); // token -> { cardSerial, citizen, expiresAt }

function sign(payload) {
  const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
  const mac = crypto.createHmac("sha256", SECRET).update(body).digest("base64url");
  return `${body}.${mac}`;
}

export function publicCitizen(c) {
  return {
    residentId: c.residentId,
    familyNameKanji: c.familyNameKanji, givenNameKanji: c.givenNameKanji,
    familyNameKana: c.familyNameKana, givenNameKana: c.givenNameKana,
    birthDate: c.birthDate, sex: c.sex, addressText: c.addressText,
  };
}

// マイナンバーカードでのログイン（利用者証明用電子証明書 + PIN の検証をシミュレート）
export function cardLogin(cardSerial, pin) {
  const now = Date.now();
  const lk = lockState.get(cardSerial);
  if (lk && lk.lockedUntil > now) {
    return { ok: false, status: 423, error: "カードが一時ロックされています。しばらく後に再度お試しください。" };
  }
  const citizen = MOCK_CITIZENS.find((c) => c.cardSerial === cardSerial);
  if (!citizen || citizen.pin !== String(pin)) {
    const fails = ((lk && lk.fails) || 0) + 1;
    if (fails >= MAX_PIN_FAILS) {
      lockState.set(cardSerial, { fails: 0, lockedUntil: now + LOCK_MS });
      return { ok: false, status: 423, error: "暗証番号を3回誤りました。カードを一時ロックしました。" };
    }
    lockState.set(cardSerial, { fails, lockedUntil: 0 });
    return { ok: false, status: 401, error: `マイナンバーカードの認証に失敗しました（残り${MAX_PIN_FAILS - fails}回）。` };
  }
  lockState.delete(cardSerial);
  const token = sign({ sub: citizen.residentId, serial: cardSerial, iat: now });
  sessions.set(token, { cardSerial, citizen, expiresAt: now + SESSION_TTL_MS });
  return { ok: true, token, citizen: publicCitizen(citizen) };
}

export function verifyToken(token) {
  if (!token) return null;
  const s = sessions.get(token);
  if (!s) return null;
  if (s.expiresAt < Date.now()) { sessions.delete(token); return null; }
  return s.citizen;
}

export function logout(token) {
  sessions.delete(token);
}

export function bearer(req) {
  const h = req.headers["authorization"];
  if (h && typeof h === "string" && h.startsWith("Bearer ")) return h.slice(7);
  return null;
}
