import * as  OTPAuth from "otpauth";
import QRCode from "qrcode";
import { query } from "../config/db.js";

export async function startTotpEnrollment(user) {
  const secret = new OTPAuth.Secret();
  const totp = new OTPAuth.TOTP({
    issuer: "BR-Office",
    label: user.email,
    algorithm: "SHA1",
    digits: 6,
    period: 30,
    secret,
  });

  await query(
    `INSERT INTO user_totp_secret(user_id, secret_base32, is_verified)
     VALUES ($1,$2,FALSE)
     ON CONFLICT (user_id) DO UPDATE SET secret_base32 = EXCLUDED.secret_base32, is_verified = FALSE, verified_at = NULL`,
    [user.id, secret.base32]
  );

  return {
    secretBase32: secret.base32,
    otpAuthUrl: totp.toString(),
    qrCodeDataUrl: await QRCode.toDataURL(totp.toString()),
  };
}

export async function verifyTotpEnrollment(user, token) {
  const result = await query(`SELECT secret_base32 FROM user_totp_secret WHERE user_id = $1`, [user.id]);
  const row = result.rows[0];
  if (!row) throw Object.assign(new Error("TOTP-Setup fehlt"), { status: 400, publicMessage: "TOTP-Setup fehlt" });

  const totp = new OTPAuth.TOTP({
    issuer: "BR-Office",
    label: user.email,
    algorithm: "SHA1",
    digits: 6,
    period: 30,
    secret: OTPAuth.Secret.fromBase32(row.secret_base32),
  });

  const delta = totp.validate({ token, window: 1 });
  if (delta === null) throw Object.assign(new Error("Ungültiger TOTP-Code"), { status: 401, publicMessage: "Ungültiger TOTP-Code" });

  await query(`UPDATE user_totp_secret SET is_verified = TRUE, verified_at = NOW() WHERE user_id = $1`, [user.id]);
  await query(`UPDATE app_user SET two_factor_enabled = TRUE, last_mfa_at = NOW() WHERE id = $1`, [user.id]);
  return { ok: true };
}

export async function verifyTotpCode(user, token) {
  const result = await query(`SELECT secret_base32, is_verified FROM user_totp_secret WHERE user_id = $1`, [user.id]);
  const row = result.rows[0];
  if (!row || !row.is_verified) return false;
  const totp = new OTPAuth.TOTP({
    issuer: "BR-Office",
    label: user.email,
    algorithm: "SHA1",
    digits: 6,
    period: 30,
    secret: OTPAuth.Secret.fromBase32(row.secret_base32),
  });
  return totp.validate({ token, window: 1 }) !== null;
}
