"use server";

import { revalidatePath } from "next/cache";
import { NotdienstPlanStatus, UserRole } from "@prisma/client";

import { requireRole } from "@/lib/auth-utils";
import { prisma } from "@/lib/prisma";
import { getTargetMonthData, getWorkingDaysOfMonth } from "@/lib/date-utils";

// =====================================================================
// /dashboard/notdienst/plan · Server Actions
// =====================================================================

export async function generatePlanAction() {
  const session = await requireRole([UserRole.ADMIN, UserRole.KOORDINATOR]);
  const kitaId = session.user.kitaId!;

  const { targetYear, targetMonth } = getTargetMonthData();

  // Prüfen, ob schon ein Plan existiert
  const existingPlan = await prisma.notdienstPlan.findUnique({
    where: {
      kitaId_year_month: { kitaId, year: targetYear, month: targetMonth },
    },
  });

  if (existingPlan) {
    return { error: "Ein Plan für diesen Monat existiert bereits." };
  }

  // 1. Alle Verfügbarkeiten der Eltern für diesen Monat holen
  const availabilities = await prisma.notdienstAvailability.findMany({
    where: {
      kitaId,
      date: {
        gte: new Date(targetYear, targetMonth - 1, 1),
        lt: new Date(targetYear, targetMonth, 1),
      },
    },
    include: { child: { select: { familyId: true } } },
  });

  // 2. Werktage holen
  const workingDays = getWorkingDaysOfMonth(targetYear, targetMonth);

  // 3. Algorithmus: Wir verteilen die Slots
  // Counter für "Gerechtigkeit": wie oft wurde diese Familie schon eingeteilt?
  const familyUsageCount: Record<string, number> = {};

  const assignmentsToCreate: { childId: string; date: Date }[] = [];

  for (const day of workingDays) {
    // Alle Verfügbarkeiten für diesen spezifischen Tag
    const availForDay = availabilities.filter(
      (a) => a.date.getTime() === day.getTime(),
    );

    if (availForDay.length === 0) {
      // Niemand verfügbar -> Bleibt leer ("Unbesetzt")
      continue;
    }

    // Finde die Familie, die am wenigsten oft dran war
    // Zufall einbauen bei Gleichstand
    const sorted = availForDay.sort((a, b) => {
      const countA = familyUsageCount[a.child.familyId] || 0;
      const countB = familyUsageCount[b.child.familyId] || 0;
      if (countA === countB) {
        return Math.random() - 0.5; // Zufallsmischung
      }
      return countA - countB;
    });

    const selected = sorted[0];

    assignmentsToCreate.push({
      childId: selected.childId,
      date: day,
    });

    // Usage-Counter erhöhen
    familyUsageCount[selected.child.familyId] =
      (familyUsageCount[selected.child.familyId] || 0) + 1;
  }

  // 4. In der DB speichern
  try {
    await prisma.$transaction(async (tx) => {
      const plan = await tx.notdienstPlan.create({
        data: {
          kitaId,
          year: targetYear,
          month: targetMonth,
          status: NotdienstPlanStatus.DRAFT,
          createdById: session.user.id,
        },
      });

      if (assignmentsToCreate.length > 0) {
        await tx.notdienstAssignment.createMany({
          data: assignmentsToCreate.map((a) => ({
            kitaId,
            planId: plan.id,
            childId: a.childId,
            date: a.date,
          })),
        });
      }
    });

    revalidatePath("/dashboard/notdienst/plan");
    return { success: true };
  } catch (error) {
    console.error(error);
    return { error: "Fehler bei der Generierung des Plans." };
  }
}

export async function publishPlanAction(planId: string) {
  const session = await requireRole([UserRole.ADMIN, UserRole.KOORDINATOR]);
  const kitaId = session.user.kitaId!;

  await prisma.notdienstPlan.update({
    where: { id: planId, kitaId },
    data: {
      status: NotdienstPlanStatus.PUBLISHED,
      publishedAt: new Date(),
    },
  });

  revalidatePath("/dashboard/notdienst/plan");
  revalidatePath("/dashboard/notdienst");
  return { success: true };
}

export async function updateAssignmentAction(
  planId: string,
  date: string,
  newChildId: string | null,
) {
  const session = await requireRole([UserRole.ADMIN, UserRole.KOORDINATOR]);
  const kitaId = session.user.kitaId!;

  const parsedDate = new Date(date);

  try {
    await prisma.$transaction(async (tx) => {
      // Prüfen, ob Plan noch DRAFT ist
      const plan = await tx.notdienstPlan.findUnique({
        where: { id: planId, kitaId },
      });

      if (!plan || plan.status !== NotdienstPlanStatus.DRAFT) {
        throw new Error("Plan kann nicht mehr bearbeitet werden.");
      }

      // Altes Assignment für diesen Tag löschen
      await tx.notdienstAssignment.deleteMany({
        where: { planId, date: parsedDate },
      });

      // Neues anlegen, falls ausgewählt
      if (newChildId) {
        const child = await tx.child.findFirst({
          where: {
            id: newChildId,
            kitaId,
            active: true,
          },
          select: { id: true },
        });

        if (!child) {
          throw new Error("Kind gehört nicht zu dieser Kita.");
        }

        await tx.notdienstAssignment.create({
          data: {
            kitaId,
            planId,
            childId: newChildId,
            date: parsedDate,
          },
        });
      }
    });

    revalidatePath("/dashboard/notdienst/plan");
    return { success: true };
  } catch (error) {
    return {
      error: error instanceof Error ? error.message : "Update fehlgeschlagen.",
    };
  }
}
