"use server";

import { revalidatePath } from "next/cache";
import { hasPermission } from "@/lib/adminAuth";
import { connectDB } from "@/lib/db";
import { Department } from "@/models/Department";
import { Position } from "@/models/Position";
import { Team } from "@/models/Team";
import { Client } from "@/models/Client";
import {
  EMPLOYMENT_TYPES,
  EMPLOYMENT_TYPE_LABELS,
  TERMINATION_TYPES,
  PROBATION_ELIGIBLE_TYPES,
  DEFAULT_ONBOARDING_CHECKLIST_ITEMS,
  type EmploymentType,
  type TerminationType,
} from "@/lib/employment";
import { PERMISSIONS } from "@/lib/permissions";
import { logTeamActivity } from "@/lib/teamActivity";

const TEAM_PATH = "/de/admin/team";

type FormState = { error?: string };

function readPositiveNumberField(formData: FormData, field: string): number | null {
  const raw = String(formData.get(field) || "").trim();
  if (!raw) return null;
  const value = Number(raw.replace(",", "."));
  return Number.isFinite(value) && value >= 0 ? value : null;
}

export async function createDepartmentAction(_prev: FormState, formData: FormData): Promise<FormState> {
  if (!(await hasPermission("team_management_create"))) return { error: "Keine Berechtigung." };
  const name = String(formData.get("name") || "").trim();
  if (!name) return { error: "Bitte einen Namen eingeben." };
  const color = String(formData.get("color") || "").trim() || "#a3a1a6";
  await connectDB();
  await Department.create({ name, color, defaultHourlyWage: readPositiveNumberField(formData, "defaultHourlyWage"), sortOrder: Date.now() });
  await logTeamActivity("Abteilung angelegt", name);
  revalidatePath(TEAM_PATH);
  return {};
}

// Eigene Action statt in updateDepartmentNameAction mit reinzunehmen - dort
// erwartet ein leeres Namensfeld ein "nichts tun", hier ist ein leeres Feld
// dagegen ein gültiges "keinen Standard-Stundenlohn mehr" (null).
export async function updateDepartmentSalaryAction(id: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  await connectDB();
  await Department.findByIdAndUpdate(id, { defaultHourlyWage: readPositiveNumberField(formData, "defaultHourlyWage") });
  revalidatePath(TEAM_PATH);
}

export async function updateDepartmentColorAction(id: string, color: string) {
  if (!(await hasPermission("team_management_edit"))) return;
  await connectDB();
  await Department.findByIdAndUpdate(id, { color });
  revalidatePath(TEAM_PATH);
  revalidatePath("/de/admin/intranet");
}

export async function deleteDepartmentAction(id: string) {
  if (!(await hasPermission("team_management_delete"))) return;
  await connectDB();
  const department = await Department.findById(id).select("name").lean();
  await Department.findByIdAndDelete(id);
  await Position.deleteMany({ departmentId: id });
  await Client.updateMany({ departmentId: id }, { $set: { departmentId: null, positionId: null } });
  await logTeamActivity("Abteilung gelöscht", department?.name ?? "");
  revalidatePath(TEAM_PATH);
}

export async function updateDepartmentNameAction(id: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  const name = String(formData.get("name") || "").trim();
  if (!name) return;
  await connectDB();
  await Department.findByIdAndUpdate(id, { name });
  revalidatePath(TEAM_PATH);
}

export async function createPositionAction(_prev: FormState, formData: FormData): Promise<FormState> {
  if (!(await hasPermission("team_management_create"))) return { error: "Keine Berechtigung." };
  const name = String(formData.get("name") || "").trim();
  const departmentId = String(formData.get("departmentId") || "");
  if (!name) return { error: "Bitte einen Namen eingeben." };
  if (!departmentId) return { error: "Bitte eine Abteilung wählen." };
  await connectDB();
  await Position.create({ name, departmentId, defaultHourlyWage: readPositiveNumberField(formData, "defaultHourlyWage"), sortOrder: Date.now() });
  await logTeamActivity("Position angelegt", name);
  revalidatePath(TEAM_PATH);
  return {};
}

export async function updatePositionSalaryAction(id: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  await connectDB();
  await Position.findByIdAndUpdate(id, { defaultHourlyWage: readPositiveNumberField(formData, "defaultHourlyWage") });
  revalidatePath(TEAM_PATH);
}

export async function deletePositionAction(id: string) {
  if (!(await hasPermission("team_management_delete"))) return;
  await connectDB();
  const position = await Position.findById(id).select("name").lean();
  await Position.findByIdAndDelete(id);
  await Client.updateMany({ positionId: id }, { $set: { positionId: null } });
  await logTeamActivity("Position gelöscht", position?.name ?? "");
  revalidatePath(TEAM_PATH);
}

export async function updatePositionNameAction(id: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  const name = String(formData.get("name") || "").trim();
  if (!name) return;
  await connectDB();
  await Position.findByIdAndUpdate(id, { name });
  revalidatePath(TEAM_PATH);
}

export async function createTeamAction(_prev: FormState, formData: FormData): Promise<FormState> {
  if (!(await hasPermission("team_management_create"))) return { error: "Keine Berechtigung." };
  const name = String(formData.get("name") || "").trim();
  const color = String(formData.get("color") || "#a3a1a6");
  if (!name) return { error: "Bitte einen Namen eingeben." };
  await connectDB();
  await Team.create({ name, color, sortOrder: Date.now() });
  revalidatePath(TEAM_PATH);
  return {};
}

export async function deleteTeamAction(id: string) {
  if (!(await hasPermission("team_management_delete"))) return;
  await connectDB();
  await Team.findByIdAndDelete(id);
  await Client.updateMany({ teamIds: id }, { $pull: { teamIds: id } });
  revalidatePath(TEAM_PATH);
}

export async function updateTeamNameAction(id: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  const name = String(formData.get("name") || "").trim();
  if (!name) return;
  await connectDB();
  await Team.findByIdAndUpdate(id, { name });
  revalidatePath(TEAM_PATH);
}

// Berechtigungen hängen an der Position, nicht am einzelnen Mitarbeiter —
// fullAccess=on setzt das Array auf null zurück (Vollzugriff, Sicherheitsnetz),
// sonst wird exakt die angehakte Liste gespeichert. Gilt für jeden Mitarbeiter
// mit dieser Position gleichzeitig.
export async function updatePositionPermissionsAction(positionId: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  const fullAccess = formData.get("fullAccess") === "on";
  await connectDB();
  const position = await Position.findById(positionId).select("name").lean();
  if (fullAccess) {
    await Position.findByIdAndUpdate(positionId, { permissions: null });
  } else {
    const permissions = PERMISSIONS.filter((p) => formData.get(`perm_${p}`) === "on");
    await Position.findByIdAndUpdate(positionId, { permissions });
  }
  await logTeamActivity(
    "Berechtigungen geändert",
    `${position?.name ?? "Position"} — ${fullAccess ? "Vollzugriff" : "eingeschränkt"}`
  );
  revalidatePath(TEAM_PATH);
}

export async function setStaffRoleAction(clientId: string, isStaff: boolean) {
  if (!(await hasPermission("team_management_edit"))) return;
  await connectDB();
  const client = await Client.findByIdAndUpdate(clientId, { role: isStaff ? "staff" : "client" }).select("name").lean();
  await logTeamActivity(isStaff ? "Zu Mitarbeiter befördert" : "Mitarbeiterstatus entfernt", client?.name ?? "");
  revalidatePath(TEAM_PATH);
  revalidatePath("/de/admin/clients");
}

export async function setBirthDateAction(clientId: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  const raw = String(formData.get("birthDate") || "");
  const date = raw ? new Date(raw) : null;
  await connectDB();
  await Client.findByIdAndUpdate(clientId, { birthDate: date && !Number.isNaN(date.getTime()) ? date : null });
  revalidatePath(`/de/admin/team/${clientId}`);
}

// Vertragliche Zielwerte (Personalsystem, 24.09.2026) - leeres Feld = kein
// eigener Wert, Vertrags-Creator greift dann auf den Positions-/Abteilungs-
// Standard zurück (siehe lib/salary.ts getEffectiveHourlyWage).
export async function setSalaryFieldsAction(clientId: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  await connectDB();
  await Client.findByIdAndUpdate(clientId, {
    hourlyWage: readPositiveNumberField(formData, "hourlyWage"),
    monthlyHours: readPositiveNumberField(formData, "monthlyHours"),
  });
  revalidatePath(`/de/admin/team/${clientId}`);
}

// Personalakte: ein neuer Beschäftigungs-Eintrag (Mitarbeiter/Teamler/
// Praktikant/Azubi mit Zeitraum) — frühere Einträge bleiben als Historie
// erhalten, nichts wird überschrieben.
export async function addEmploymentRecordAction(clientId: string, formData: FormData) {
  if (!(await hasPermission("team_management_create"))) return { error: "Keine Berechtigung." };
  const type = String(formData.get("type") || "");
  if (!EMPLOYMENT_TYPES.includes(type as EmploymentType)) return { error: "Bitte eine Art auswählen." };

  const startRaw = String(formData.get("startDate") || "");
  const start = startRaw ? new Date(startRaw) : null;
  if (!start || Number.isNaN(start.getTime())) return { error: "Bitte ein gültiges Startdatum angeben." };

  const endRaw = String(formData.get("endDate") || "");
  const end = endRaw ? new Date(endRaw) : null;
  if (end && (Number.isNaN(end.getTime()) || end <= start)) return { error: "Das Enddatum muss nach dem Start liegen." };

  const probationRaw = String(formData.get("probationMonths") || "");
  const probationMonths = probationRaw ? Number(probationRaw) : null;
  const validProbation =
    PROBATION_ELIGIBLE_TYPES.includes(type as (typeof PROBATION_ELIGIBLE_TYPES)[number]) &&
    probationMonths !== null &&
    Number.isFinite(probationMonths) &&
    probationMonths >= 1 &&
    probationMonths <= 24
      ? probationMonths
      : null;

  const terminationRaw = String(formData.get("terminationType") || "");
  const terminationType =
    type === "termination" && TERMINATION_TYPES.includes(terminationRaw as TerminationType)
      ? (terminationRaw as TerminationType)
      : null;
  if (type === "termination" && !terminationType) return { error: "Bitte eine Kündigungsart auswählen." };

  await connectDB();

  // Onboarding-Checkliste einmalig mit Standardpunkten vorbefüllen — nur
  // beim ersten "echten" Beschäftigungs-Eintrag (nicht bei Kündigung/Notiz),
  // und nur, falls noch keine Checkliste existiert (kein Überschreiben bei
  // einem zweiten Beschäftigungsabschnitt derselben Person).
  const isRealEmploymentStart = ["employee", "team_member", "intern", "apprentice"].includes(type);
  const existing = isRealEmploymentStart ? await Client.findById(clientId).select("onboardingChecklist").lean() : null;
  const shouldSeedChecklist = isRealEmploymentStart && existing && existing.onboardingChecklist.length === 0;

  const client = await Client.findByIdAndUpdate(
    clientId,
    {
      $push: {
        employmentRecords: {
          type,
          startDate: start,
          endDate: end,
          probationMonths: validProbation,
          probationReminderSent: false,
          terminationType,
          note: String(formData.get("note") || "").trim(),
        },
      },
      ...(shouldSeedChecklist
        ? { $set: { onboardingChecklist: DEFAULT_ONBOARDING_CHECKLIST_ITEMS.map((text) => ({ text, done: false, doneAt: null })) } }
        : {}),
    },
    { new: true }
  ).select("name");
  await logTeamActivity("Personalakte: Eintrag hinzugefügt", `${client?.name ?? ""} — ${EMPLOYMENT_TYPE_LABELS[type as EmploymentType]}`);
  revalidatePath(`/de/admin/team/${clientId}`);
  return {};
}

export async function deleteEmploymentRecordAction(clientId: string, recordId: string) {
  if (!(await hasPermission("team_management_delete"))) return;
  await connectDB();
  const client = await Client.findByIdAndUpdate(clientId, { $pull: { employmentRecords: { _id: recordId } } }, { new: true }).select(
    "name"
  );
  await logTeamActivity("Personalakte: Eintrag gelöscht", client?.name ?? "");
  revalidatePath(`/de/admin/team/${clientId}`);
}

export async function assignStaffAction(clientId: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  const departmentId = String(formData.get("departmentId") || "") || null;
  const positionId = String(formData.get("positionId") || "") || null;
  const teamIds = formData.getAll("teamIds").map(String);

  await connectDB();
  const [client, department, position] = await Promise.all([
    Client.findByIdAndUpdate(clientId, { departmentId, positionId, teamIds }).select("name").lean(),
    departmentId ? Department.findById(departmentId).select("name").lean() : null,
    positionId ? Position.findById(positionId).select("name").lean() : null,
  ]);
  await logTeamActivity(
    "Abteilung/Position zugewiesen",
    `${client?.name ?? ""} — ${department?.name ?? "keine Abteilung"} / ${position?.name ?? "keine Position"}`
  );
  revalidatePath(TEAM_PATH);
  revalidatePath("/de/admin/clients");
}

// Onboarding-Checkliste — gleiches Muster wie actions/orderChecklist.ts,
// nur auf Client statt Order.
export async function toggleOnboardingItemAction(clientId: string, itemId: string, done: boolean) {
  if (!(await hasPermission("team_management_edit"))) return;
  await connectDB();
  await Client.updateOne(
    { _id: clientId },
    { $set: { "onboardingChecklist.$[item].done": done, "onboardingChecklist.$[item].doneAt": done ? new Date() : null } },
    { arrayFilters: [{ "item._id": itemId }] }
  );
  revalidatePath(`/de/admin/team/${clientId}`);
}

export async function addOnboardingItemAction(clientId: string, text: string) {
  if (!(await hasPermission("team_management_edit"))) return;
  const trimmed = text.trim();
  if (!trimmed) return;
  await connectDB();
  await Client.updateOne({ _id: clientId }, { $push: { onboardingChecklist: { text: trimmed, done: false, doneAt: null } } });
  revalidatePath(`/de/admin/team/${clientId}`);
}

export async function deleteOnboardingItemAction(clientId: string, itemId: string) {
  if (!(await hasPermission("team_management_edit"))) return;
  await connectDB();
  await Client.updateOne({ _id: clientId }, { $pull: { onboardingChecklist: { _id: itemId } } });
  revalidatePath(`/de/admin/team/${clientId}`);
}
