"use server";

import { revalidatePath } from "next/cache";
import { AbsenceReason, UserRole } from "@prisma/client";
import { z } from "zod";

import { requireKitaSession, requireRole } from "@/lib/auth-utils";
import { prisma } from "@/lib/prisma";

const reportAbsenceSchema = z.object({
  childId: z.string().min(1),
  startDate: z.string().min(1),
  endDate: z.string().min(1),
  reason: z.nativeEnum(AbsenceReason),
  note: z.string().trim().max(500).optional(),
});

const dailyAbsenceSchema = z.object({
  date: z.string().min(1),
});

export type DailyAbsenceDto = {
  id: string;
  childName: string;
  familyName: string;
  reason: AbsenceReason;
  note: string | null;
  startDate: string;
  endDate: string;
};

function parseDateOnly(value: string) {
  const date = new Date(`${value.slice(0, 10)}T00:00:00`);
  if (Number.isNaN(date.getTime())) {
    throw new Error("Ungueltiges Datum.");
  }
  return date;
}

function toDateKey(date: Date) {
  return date.toISOString().slice(0, 10);
}

export async function reportAbsence(rawPayload: unknown) {
  const session = await requireKitaSession();
  const parsed = reportAbsenceSchema.safeParse(rawPayload);

  if (!parsed.success) {
    return { error: "Ungültige Eingabedaten." };
  }

  if (!session.user.familyId) {
    return { error: "Dein Account ist noch keinem Haushalt zugeordnet." };
  }

  const startDate = parseDateOnly(parsed.data.startDate);
  const endDate = parseDateOnly(parsed.data.endDate);

  if (endDate < startDate) {
    return { error: "Das Enddatum darf nicht vor dem Startdatum liegen." };
  }

  const child = await prisma.child.findFirst({
    where: {
      id: parsed.data.childId,
      kitaId: session.user.kitaId,
      familyId: session.user.familyId,
      active: true,
    },
    select: { id: true },
  });

  if (!child) {
    return { error: "Dieses Kind gehört nicht zu deinem Haushalt." };
  }

  const overlappingAbsence = await prisma.absence.findFirst({
    where: {
      kitaId: session.user.kitaId,
      childId: child.id,
      startDate: { lte: endDate },
      endDate: { gte: startDate },
    },
    select: { id: true },
  });

  if (overlappingAbsence) {
    return { error: "Für diesen Zeitraum existiert bereits eine Abmeldung." };
  }

  await prisma.absence.create({
    data: {
      kitaId: session.user.kitaId,
      childId: child.id,
      startDate,
      endDate,
      reason: parsed.data.reason,
      note: parsed.data.note || null,
    },
  });

  revalidatePath("/dashboard");
  revalidatePath("/dashboard/admin/abwesenheiten");
  return { success: true };
}

export async function deleteAbsence(id: string) {
  const session = await requireKitaSession();

  if (!session.user.familyId) {
    return { error: "Dein Account ist noch keinem Haushalt zugeordnet." };
  }

  const absence = await prisma.absence.findFirst({
    where: {
      id,
      kitaId: session.user.kitaId,
      child: {
        familyId: session.user.familyId,
      },
    },
    select: { id: true },
  });

  if (!absence) {
    return { error: "Diese Abmeldung gehört nicht zu deinem Haushalt." };
  }

  await prisma.absence.delete({
    where: { id: absence.id },
  });

  revalidatePath("/dashboard");
  revalidatePath("/dashboard/admin/abwesenheiten");
  return { success: true };
}

export async function getDailyAbsences(
  rawPayload: unknown,
): Promise<{ absences?: DailyAbsenceDto[]; error?: string }> {
  const session = await requireRole([
    UserRole.ADMIN,
    UserRole.KOORDINATOR,
    UserRole.ERZIEHER,
  ]);

  if (!session.user.kitaId) {
    return { error: "Kein Mandant zugeordnet." };
  }

  const parsed = dailyAbsenceSchema.safeParse(rawPayload);
  if (!parsed.success) {
    return { error: "Ungültiges Datum." };
  }

  const date = parseDateOnly(parsed.data.date);
  const rows = await prisma.absence.findMany({
    where: {
      kitaId: session.user.kitaId,
      startDate: { lte: date },
      endDate: { gte: date },
    },
    select: {
      id: true,
      reason: true,
      note: true,
      startDate: true,
      endDate: true,
      child: {
        select: {
          firstName: true,
          lastName: true,
          family: {
            select: {
              name: true,
            },
          },
        },
      },
    },
    orderBy: [
      { child: { lastName: "asc" } },
      { child: { firstName: "asc" } },
    ],
  });

  return {
    absences: rows.map((absence) => ({
      id: absence.id,
      childName: `${absence.child.firstName} ${absence.child.lastName}`,
      familyName: absence.child.family.name,
      reason: absence.reason,
      note: absence.note,
      startDate: toDateKey(absence.startDate),
      endDate: toDateKey(absence.endDate),
    })),
  };
}
