"use server";

import { Types } from "mongoose";
import { revalidatePath } from "next/cache";
import { hasPermission } from "@/lib/adminAuth";
import { getSessionClientId } from "@/lib/auth";
import { connectDB } from "@/lib/db";
import { Client } from "@/models/Client";
import { VacationRequest } from "@/models/VacationRequest";
import { countVacationWorkDays } from "@/lib/vacationConstants";
import { remainingVacationDays } from "@/lib/vacationBalance";

// Kontingent pro Mitarbeiter - gleiches Muster/gleiche Berechtigung wie
// setSalaryFieldsAction in actions/team.ts.
export async function setVacationAllowanceAction(clientId: string, formData: FormData) {
  if (!(await hasPermission("team_management_edit"))) return;
  await connectDB();
  const raw = String(formData.get("vacationDaysPerYear") || "").trim();
  const value = raw === "" ? null : Number(raw);
  if (value !== null && (!Number.isFinite(value) || value < 0)) return;
  await Client.findByIdAndUpdate(clientId, { $set: { vacationDaysPerYear: value } });
  revalidatePath(`/de/admin/team/${clientId}`);
}

// Selbstbedienung - jede:r Mitarbeiter:in beantragt für sich selbst.
// Jahresübergreifende Zeiträume werden bewusst abgelehnt (siehe
// vacationConstants.ts), damit die Resturlaubs-Berechnung pro Kalenderjahr
// einfach und eindeutig bleibt. "Verhindert/warnt" (Nutzer-Wunsch) wurde
// bewusst als nicht-blockierende Warnung umgesetzt, gleiches Muster wie die
// ArbZG-Hinweise in workingTimeCompliance.ts - HR bleibt die tatsächliche
// Freigabe-Instanz und kann trotzdem genehmigen (z. B. bei Korrektur eines
// zu niedrig gepflegten Kontingents).
export async function requestVacationAction(formData: FormData) {
  const clientId = await getSessionClientId();
  if (!clientId) return { error: "Nicht angemeldet." };

  const startRaw = String(formData.get("startDate") || "");
  const endRaw = String(formData.get("endDate") || "");
  const start = startRaw ? new Date(startRaw) : null;
  const end = endRaw ? new Date(endRaw) : null;
  if (!start || Number.isNaN(start.getTime()) || !end || Number.isNaN(end.getTime())) {
    return { error: "Bitte einen gültigen Zeitraum angeben." };
  }
  if (end.getTime() < start.getTime()) return { error: "Das Enddatum darf nicht vor dem Startdatum liegen." };
  if (start.getFullYear() !== end.getFullYear()) {
    return { error: "Bitte jahresübergreifende Urlaube als zwei separate Anträge stellen." };
  }

  const workDaysCount = countVacationWorkDays(start, end);
  if (workDaysCount === 0) return { error: "Der gewählte Zeitraum enthält keine Werktage." };

  await connectDB();
  const year = start.getFullYear();
  const [client, existing] = await Promise.all([
    Client.findById(clientId).select("vacationDaysPerYear").lean(),
    VacationRequest.find({
      clientId,
      status: { $in: ["requested", "approved"] },
      startDate: { $gte: new Date(year, 0, 1), $lt: new Date(year + 1, 0, 1) },
    })
      .select("status workDaysCount")
      .lean(),
  ]);

  const allowance = client?.vacationDaysPerYear ?? null;
  const balance = remainingVacationDays(allowance, existing);
  let warning: string | null = null;
  if (allowance !== null && balance.approvedDays + balance.pendingDays + workDaysCount > allowance) {
    warning = `Achtung: Damit wären ${balance.approvedDays + balance.pendingDays + workDaysCount} von ${allowance} Urlaubstagen für ${year} beantragt/genommen.`;
  }

  await VacationRequest.create({
    clientId: new Types.ObjectId(clientId),
    startDate: start,
    endDate: end,
    workDaysCount,
    note: String(formData.get("note") || "").trim(),
  });

  revalidatePath("/de/account/mitarbeiter");
  revalidatePath("/de/admin/urlaubsantraege");
  return { warning };
}

// Nur die eigenen, noch nicht final entschiedenen ODER bereits genehmigten
// (aber noch bevorstehenden) Anträge lassen sich zurückziehen - abgelehnte/
// bereits zurückgezogene bleiben als Verlauf stehen.
export async function cancelVacationRequestAction(requestId: string) {
  const clientId = await getSessionClientId();
  if (!clientId) return;
  await connectDB();
  await VacationRequest.updateOne(
    { _id: requestId, clientId, status: { $in: ["requested", "approved"] } },
    { $set: { status: "cancelled" } }
  );
  revalidatePath("/de/account/mitarbeiter");
  revalidatePath("/de/admin/urlaubsantraege");
}

export async function approveVacationRequestAction(requestId: string) {
  if (!(await hasPermission("hr"))) return;
  const decidedBy = await getSessionClientId();
  if (!decidedBy) return;
  await connectDB();
  await VacationRequest.updateOne(
    { _id: requestId, status: "requested" },
    { $set: { status: "approved", decidedByClientId: new Types.ObjectId(decidedBy), decidedAt: new Date() } }
  );
  revalidatePath("/de/account/mitarbeiter");
  revalidatePath("/de/admin/urlaubsantraege");
}

export async function rejectVacationRequestAction(requestId: string, formData: FormData) {
  if (!(await hasPermission("hr"))) return;
  const decidedBy = await getSessionClientId();
  if (!decidedBy) return;
  await connectDB();
  await VacationRequest.updateOne(
    { _id: requestId, status: "requested" },
    {
      $set: {
        status: "rejected",
        decidedByClientId: new Types.ObjectId(decidedBy),
        decidedAt: new Date(),
        rejectionReason: String(formData.get("rejectionReason") || "").trim(),
      },
    }
  );
  revalidatePath("/de/account/mitarbeiter");
  revalidatePath("/de/admin/urlaubsantraege");
}
