"use server";

import { revalidatePath } from "next/cache";
import { hasPermission } from "@/lib/adminAuth";
import { hashPassword } from "@/lib/auth";
import { connectDB } from "@/lib/db";
import { Client } from "@/models/Client";
import { logTeamActivity } from "@/lib/teamActivity";
import { clientHasInvoices, hardDeleteClient, anonymizeClient } from "@/lib/accountDeletion";
import { formatAddress } from "@/lib/orderConstants";

type FormState = { error?: string; success?: boolean };
type CreateClientState = { error?: string; clientId?: string };

const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

export async function adminCreateClientAction(_prev: CreateClientState, formData: FormData): Promise<CreateClientState> {
  // Gleiche enge Berechtigung wie beim Passwort setzen: ein neues Kundenkonto
  // im Namen eines Kunden anzulegen ist ein sensibler Eingriff, kein reines Ansehen.
  if (!(await hasPermission("client_accounts"))) return { error: "Keine Berechtigung." };

  const firstName = String(formData.get("firstName") || "").trim();
  const lastName = String(formData.get("lastName") || "").trim();
  const nickname = String(formData.get("nickname") || "").trim();
  const email = String(formData.get("email") || "").trim().toLowerCase();
  const password = String(formData.get("password") || "");
  const birthDateRaw = String(formData.get("birthDate") || "");
  const phone = String(formData.get("phone") || "").trim();
  const billingStreet = String(formData.get("billingStreet") || "").trim();
  const billingPostCode = String(formData.get("billingPostCode") || "").trim();
  const billingCity = String(formData.get("billingCity") || "").trim();
  const billingCountryCode = String(formData.get("billingCountryCode") || "DE").trim();
  const locale: "de" | "en" = formData.get("locale") === "en" ? "en" : "de";

  if (!firstName || !lastName) return { error: "Bitte Vor- und Nachnamen eingeben." };
  if (!EMAIL_RE.test(email)) return { error: "Ungültige E-Mail-Adresse." };
  if (password.length < 8) return { error: "Passwort muss mindestens 8 Zeichen haben." };
  const birthDate = birthDateRaw ? new Date(birthDateRaw) : null;
  if (!birthDate || Number.isNaN(birthDate.getTime()) || birthDate.getTime() > Date.now()) {
    return { error: "Bitte ein gültiges Geburtsdatum eingeben." };
  }
  if (phone.replace(/\D/g, "").length < 5) return { error: "Bitte eine gültige Telefonnummer eingeben." };
  if (!billingStreet || !billingPostCode || !billingCity) return { error: "Bitte eine vollständige Anschrift eingeben." };

  await connectDB();
  const existing = await Client.findOne({ email });
  if (existing) return { error: "Für diese E-Mail-Adresse existiert bereits ein Konto." };

  const passwordHash = await hashPassword(password);
  const name = `${firstName} ${lastName}`.trim();

  const client = await Client.create({
    name,
    firstName,
    lastName,
    nickname,
    email,
    passwordHash,
    locale,
    birthDate,
    phone,
    billingStreet,
    billingPostCode,
    billingCity,
    billingCountryCode: billingCountryCode || "DE",
    address: formatAddress({ street: billingStreet, postCode: billingPostCode, city: billingCity, countryCode: billingCountryCode }),
    // Vor-Ort angelegt und vom Team persönlich bestätigt — keine separate
    // E-Mail-Verifizierung nötig, im Gegensatz zur Selbstregistrierung.
    verified: true,
    // Das eingegebene Passwort ist ein Übergangspasswort, das mündlich
    // weitergegeben wird — beim ersten Login zwingend zu ändern (siehe
    // Client.mustChangePassword + actions/auth.ts loginAction).
    mustChangePassword: true,
  });
  await logTeamActivity("Kundenkonto vor Ort angelegt", client.name);

  revalidatePath("/de/admin/clients");
  return { clientId: String(client._id) };
}

export async function updateClientAccountAction(clientId: string, _prev: FormState, formData: FormData): Promise<FormState> {
  // Bewusst eine eigene, engere Berechtigung als "clients" (reine Akten-Einsicht) —
  // Passwort setzen und Stammdaten/Unternehmensdaten ändern sind sensible Eingriffe
  // ins Kundenkonto und sollen nicht automatisch jedem mit Kundenzugriff offenstehen.
  if (!(await hasPermission("client_accounts"))) return { error: "Keine Berechtigung." };

  const firstName = String(formData.get("firstName") || "").trim();
  const lastName = String(formData.get("lastName") || "").trim();
  const salutationRaw = String(formData.get("salutation") || "").trim();
  const salutation = salutationRaw === "herr" || salutationRaw === "frau" || salutationRaw === "divers" ? salutationRaw : "";
  const pronouns = salutation === "divers" ? String(formData.get("pronouns") || "").trim() : "";
  const nickname = String(formData.get("nickname") || "").trim();
  const email = String(formData.get("email") || "").trim().toLowerCase();
  const phone = String(formData.get("phone") || "").trim();
  const billingStreet = String(formData.get("billingStreet") || "").trim();
  const billingPostCode = String(formData.get("billingPostCode") || "").trim();
  const billingCity = String(formData.get("billingCity") || "").trim();
  const billingCountryCode = String(formData.get("billingCountryCode") || "DE").trim();
  const company = String(formData.get("company") || "").trim();
  const password = String(formData.get("password") || "");

  if (!firstName || !lastName) return { error: "Bitte Vor- und Nachnamen angeben." };
  if (!EMAIL_RE.test(email)) return { error: "Ungültige E-Mail-Adresse." };
  if (password && password.length < 8) {
    return { error: "Neues Passwort muss mindestens 8 Zeichen haben." };
  }

  await connectDB();
  const client = await Client.findById(clientId);
  if (!client) return { error: "Kunde nicht gefunden." };

  if (email !== client.email) {
    const existing = await Client.findOne({ email, _id: { $ne: clientId } }).select("_id").lean();
    if (existing) return { error: "Für diese E-Mail-Adresse existiert bereits ein anderes Konto." };
  }

  client.firstName = firstName;
  client.lastName = lastName;
  client.name = `${firstName} ${lastName}`.trim();
  // Nur für Kundenkonten Pflichtfeld (siehe registerAction) — ein
  // Mitarbeiter-Konto, das hier zufällig geöffnet wird, soll dadurch nicht
  // blockiert werden.
  if (client.role === "client") {
    if (!salutation) return { error: "Bitte eine Anrede auswählen." };
    client.salutation = salutation;
    client.pronouns = pronouns;
  }
  client.nickname = nickname;
  client.email = email;
  client.phone = phone;
  client.billingStreet = billingStreet;
  client.billingPostCode = billingPostCode;
  client.billingCity = billingCity;
  client.billingCountryCode = billingCountryCode || "DE";
  client.address = formatAddress({
    street: billingStreet,
    postCode: billingPostCode,
    city: billingCity,
    countryCode: billingCountryCode,
  });
  client.company = company;
  if (password) {
    client.passwordHash = await hashPassword(password);
    // Auch bei einem nachträglich vom Team gesetzten Passwort gilt es als
    // Übergangspasswort — derselbe Zwang wie bei der Erstanlage.
    client.mustChangePassword = true;
  }
  await client.save();
  await logTeamActivity(password ? "Kundenpasswort gesetzt" : "Kundenstammdaten geändert", client.name);

  revalidatePath(`/de/admin/clients/${clientId}`);
  // Dasselbe Panel sitzt seit 01.10.2026 auch in der Personalakte
  // (Mitarbeiter hatten dort keine Möglichkeit, Name/E-Mail/Passwort zu
  // ändern, siehe ClientAccountPanel-Einbindung in admin/team/[clientId]).
  revalidatePath(`/de/admin/team/${clientId}`);
  return { success: true };
}

type DeleteClientResult = { error?: string; deleted?: boolean; anonymized?: boolean };

export async function adminDeleteClientAction(clientId: string): Promise<DeleteClientResult> {
  if (!(await hasPermission("client_accounts"))) return { error: "Keine Berechtigung." };

  await connectDB();
  const client = await Client.findById(clientId);
  if (!client || client.role !== "client") return { error: "Kunde nicht gefunden." };

  const name = client.name;
  const hasInvoices = await clientHasInvoices(clientId);

  if (hasInvoices) {
    // Rechnungen müssen 10 Jahre aufbewahrt werden (§ 147 AO) — daher keine
    // harte Löschung möglich, stattdessen werden die Personendaten überschrieben.
    await anonymizeClient(clientId);
    await logTeamActivity("Kundenkonto anonymisiert (Rechnungen vorhanden)", name);
    revalidatePath(`/de/admin/clients/${clientId}`);
    return { anonymized: true };
  }

  await hardDeleteClient(clientId);
  await logTeamActivity("Kundenkonto gelöscht", name);
  revalidatePath("/de/admin/clients");
  return { deleted: true };
}

export async function setClientTagsAction(clientId: string, tags: string[]) {
  if (!(await hasPermission("clients_edit"))) return;
  const cleaned = [...new Set(tags.map((t) => t.trim()).filter(Boolean))].slice(0, 20);
  await connectDB();
  await Client.findByIdAndUpdate(clientId, { tags: cleaned });
  revalidatePath(`/de/admin/clients/${clientId}`);
  revalidatePath("/de/admin/clients");
}
