import { connectDB } from "@/lib/db";
import { Client } from "@/models/Client";
import { verifyPassword } from "@/lib/auth";

// Extrahiert aus loginAction (src/lib/actions/auth.ts) — von dort UND von der
// Team-App-API (api/team/v1/login) genutzt, damit Lockout/Passwort/2FA-Logik
// nur an einer Stelle existiert. Gibt bewusst Status-Codes statt fertiger
// Texte zurück: loginAction braucht EN/DE-Meldungen fürs Web-Formular, die
// Team-API (nur Deutsch) baut sich ihre eigenen daraus — beide aus derselben
// Prüfung, keine zwei Implementierungen, die auseinanderdriften könnten.
const LOGIN_MAX_ATTEMPTS = 5;
const LOGIN_LOCKOUT_MINUTES = 15;

export type CredentialCheckResult =
  | { ok: false; reason: "invalid" }
  | { ok: false; reason: "locked"; minutesLeft: number }
  | { ok: false; reason: "unverified" }
  | { ok: false; reason: "staff-only" }
  | { ok: true; status: "password-change-required"; clientId: string }
  | { ok: true; status: "2fa-required"; clientId: string }
  | { ok: true; status: "authenticated"; client: NonNullable<Awaited<ReturnType<typeof Client.findOne>>> };

export async function checkCredentials(
  email: string,
  password: string,
  opts?: { requireStaff?: boolean }
): Promise<CredentialCheckResult> {
  await connectDB();
  const client = await Client.findOne({ email: email.trim().toLowerCase() });

  if (!client) return { ok: false, reason: "invalid" };

  if (client.lockedUntil && client.lockedUntil.getTime() > Date.now()) {
    const minutesLeft = Math.ceil((client.lockedUntil.getTime() - Date.now()) / 60000);
    return { ok: false, reason: "locked", minutesLeft };
  }

  const valid = await verifyPassword(password, client.passwordHash);
  if (!valid) {
    const failedLoginCount = (client.failedLoginCount || 0) + 1;
    const lockedUntil = failedLoginCount >= LOGIN_MAX_ATTEMPTS ? new Date(Date.now() + LOGIN_LOCKOUT_MINUTES * 60 * 1000) : null;
    await Client.findByIdAndUpdate(client._id, { failedLoginCount, lockedUntil });
    if (lockedUntil) return { ok: false, reason: "locked", minutesLeft: LOGIN_LOCKOUT_MINUTES };
    return { ok: false, reason: "invalid" };
  }

  if (client.failedLoginCount || client.lockedUntil) {
    await Client.findByIdAndUpdate(client._id, { failedLoginCount: 0, lockedUntil: null });
  }

  if (!client.verified) return { ok: false, reason: "unverified" };

  // Muss vor 2FA/Passwort-Wechsel geprüft werden — ein Kundenkonto soll über
  // die Team-App gar nicht erst einen Pending-Token bekommen, egal wie weit
  // die Zugangsdaten sonst passen.
  if (opts?.requireStaff && client.role !== "staff") return { ok: false, reason: "staff-only" };

  if (client.mustChangePassword) return { ok: true, status: "password-change-required", clientId: String(client._id) };
  if (client.totpEnabled) return { ok: true, status: "2fa-required", clientId: String(client._id) };

  return { ok: true, status: "authenticated", client };
}
