"use server";

import bcrypt from "bcryptjs";
import QRCode from "qrcode";
import { getSessionClientId } from "@/lib/auth";
import { verifyPassword } from "@/lib/auth";
import { connectDB } from "@/lib/db";
import { Client } from "@/models/Client";
import { generateTotpSecret, verifyTotpToken, buildOtpAuthUrl, generateRecoveryCodes } from "@/lib/totp";

// Ursprünglich staff-only (daher der Name) — 2FA steht inzwischen jedem
// eingeloggten Konto offen, Kunden eingeschlossen; die Prüfung bleibt aber
// als eigene Funktion bestehen, da "eingeloggt" allein (ohne Rollen-Check)
// künftige Einschränkungen an einer Stelle erlauben würde.
async function requireStaffClient() {
  const clientId = await getSessionClientId();
  if (!clientId) return null;
  await connectDB();
  const client = await Client.findById(clientId);
  if (!client) return null;
  return client;
}

type SetupResult = { error?: string; secret?: string; qrDataUrl?: string };

// Erzeugt ein neues Secret und speichert es schon am Client — totpEnabled
// bleibt aber false, bis confirmTotpSetupAction() einen echten Code aus der
// Authenticator-App bestätigt hat. So kann ein abgebrochener Setup-Versuch
// niemanden aussperren.
export async function initiateTotpSetupAction(): Promise<SetupResult> {
  const client = await requireStaffClient();
  if (!client) return { error: "Keine Berechtigung." };
  if (client.totpEnabled) return { error: "Zwei-Faktor-Login ist bereits aktiv." };

  const secret = generateTotpSecret();
  client.totpSecret = secret;
  await client.save();

  const otpAuthUrl = buildOtpAuthUrl(secret, client.email);
  const qrDataUrl = await QRCode.toDataURL(otpAuthUrl, { margin: 1, width: 240 });

  return { secret, qrDataUrl };
}

type ConfirmResult = { error?: string; success?: boolean; recoveryCodes?: string[] };

export async function confirmTotpSetupAction(_prev: ConfirmResult, formData: FormData): Promise<ConfirmResult> {
  const client = await requireStaffClient();
  if (!client) return { error: "Keine Berechtigung." };
  if (!client.totpSecret) return { error: "Bitte zuerst die Einrichtung starten." };

  const code = String(formData.get("code") || "").trim();
  if (!verifyTotpToken(client.totpSecret, code)) return { error: "Code ungültig — bitte erneut versuchen." };

  const recoveryCodes = generateRecoveryCodes();
  client.totpEnabled = true;
  client.totpRecoveryCodeHashes = await Promise.all(recoveryCodes.map((c) => bcrypt.hash(c, 10)));
  await client.save();

  return { success: true, recoveryCodes };
}

type PasswordGatedResult = { error?: string; success?: boolean; recoveryCodes?: string[] };

export async function disableTotpAction(_prev: PasswordGatedResult, formData: FormData): Promise<PasswordGatedResult> {
  const client = await requireStaffClient();
  if (!client) return { error: "Keine Berechtigung." };

  const password = String(formData.get("password") || "");
  const valid = await verifyPassword(password, client.passwordHash);
  if (!valid) return { error: "Passwort falsch." };

  client.totpEnabled = false;
  client.totpSecret = "";
  client.totpRecoveryCodeHashes = [];
  await client.save();

  return { success: true };
}

export async function regenerateRecoveryCodesAction(
  _prev: PasswordGatedResult,
  formData: FormData
): Promise<PasswordGatedResult> {
  const client = await requireStaffClient();
  if (!client) return { error: "Keine Berechtigung." };
  if (!client.totpEnabled) return { error: "Zwei-Faktor-Login ist nicht aktiv." };

  const password = String(formData.get("password") || "");
  const valid = await verifyPassword(password, client.passwordHash);
  if (!valid) return { error: "Passwort falsch." };

  const recoveryCodes = generateRecoveryCodes();
  client.totpRecoveryCodeHashes = await Promise.all(recoveryCodes.map((c) => bcrypt.hash(c, 10)));
  await client.save();

  return { success: true, recoveryCodes };
}
