"use server";

import { createElement } from "react";
import { revalidatePath } from "next/cache";
import { DutyAssignmentStatus, UserRole } from "@prisma/client";
import { endOfWeek, format, startOfDay, startOfWeek } from "date-fns";
import { de } from "date-fns/locale";
import { z } from "zod";

import { DutyReminderEmail } from "@/emails/DutyReminderEmail";
import { requireRole } from "@/lib/auth-utils";
import { getAppEmailConfigError, sendAppEmail } from "@/lib/mail";
import { prisma } from "@/lib/prisma";

const dutyTypeSchema = z.object({
  name: z.string().trim().min(2).max(60),
  description: z.string().trim().max(240).optional(),
});

const assignmentSchema = z.object({
  dutyTypeId: z.string().min(1),
  familyId: z.string().nullable(),
  startDate: z.string().min(1),
  endDate: z.string().min(1),
});

async function requireDutyAdmin() {
  const session = await requireRole([UserRole.ADMIN, UserRole.SUPERADMIN]);
  if (!session.user.kitaId) {
    throw new Error("Kein Mandant zugeordnet.");
  }
  return { session, kitaId: session.user.kitaId };
}

function parseDateOnly(value: string) {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) {
    throw new Error("Ungueltiges Datum.");
  }
  return startOfDay(date);
}

export async function createDutyType(formData: FormData) {
  const { kitaId } = await requireDutyAdmin();
  const parsed = dutyTypeSchema.safeParse({
    name: formData.get("name"),
    description: formData.get("description") || undefined,
  });

  if (!parsed.success) {
    return;
  }

  try {
    await prisma.dutyType.create({
      data: {
        kitaId,
        name: parsed.data.name,
        description: parsed.data.description,
      },
    });
    revalidatePath("/dashboard/admin/dienste");
  } catch (error) {
    console.error("Fehler beim Erstellen des Diensttyps:", error);
  }
}

export async function deleteDutyType(formData: FormData) {
  const { kitaId } = await requireDutyAdmin();
  const dutyTypeId = String(formData.get("dutyTypeId") ?? "");

  if (!dutyTypeId) {
    return;
  }

  await prisma.dutyType.deleteMany({
    where: { id: dutyTypeId, kitaId },
  });
  revalidatePath("/dashboard/admin/dienste");
  revalidatePath("/dashboard/kalender");
  revalidatePath("/dashboard");
}

export async function upsertDutyAssignment(rawPayload: unknown) {
  const { kitaId } = await requireDutyAdmin();
  const parsed = assignmentSchema.safeParse(rawPayload);

  if (!parsed.success) {
    return { error: "Ungueltige Eingabedaten." };
  }

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

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

  const dutyType = await prisma.dutyType.findFirst({
    where: { id: parsed.data.dutyTypeId, kitaId },
    select: { id: true },
  });

  if (!dutyType) {
    return { error: "Diensttyp gehoert nicht zu dieser Kita." };
  }

  if (!parsed.data.familyId) {
    await prisma.dutyAssignment.deleteMany({
      where: {
        kitaId,
        dutyTypeId: parsed.data.dutyTypeId,
        startDate,
      },
    });
    revalidatePath("/dashboard/admin/dienste");
    revalidatePath("/dashboard/kalender");
    revalidatePath("/dashboard");
    return { success: true };
  }

  const family = await prisma.family.findFirst({
    where: { id: parsed.data.familyId, kitaId },
    select: { id: true },
  });

  if (!family) {
    return { error: "Familie gehoert nicht zu dieser Kita." };
  }

  await prisma.dutyAssignment.upsert({
    where: {
      kitaId_dutyTypeId_startDate: {
        kitaId,
        dutyTypeId: parsed.data.dutyTypeId,
        startDate,
      },
    },
    create: {
      kitaId,
      dutyTypeId: parsed.data.dutyTypeId,
      familyId: parsed.data.familyId,
      startDate,
      endDate,
      status: DutyAssignmentStatus.PLANNED,
    },
    update: {
      familyId: parsed.data.familyId,
      endDate,
      status: DutyAssignmentStatus.PLANNED,
      reminderSentAt: null,
    },
  });

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

export async function checkAndSendDutyReminders() {
  const { kitaId } = await requireDutyAdmin();
  const configError = getAppEmailConfigError();

  if (configError) {
    return { error: configError };
  }

  const now = new Date();
  const weekStart = startOfWeek(now, { weekStartsOn: 1 });
  const weekEnd = endOfWeek(now, { weekStartsOn: 1 });

  const assignments = await prisma.dutyAssignment.findMany({
    where: {
      kitaId,
      status: DutyAssignmentStatus.PLANNED,
      reminderSentAt: null,
      startDate: {
        gte: startOfDay(weekStart),
        lte: startOfDay(weekEnd),
      },
    },
    select: {
      id: true,
      startDate: true,
      endDate: true,
      dutyType: {
        select: {
          name: true,
        },
      },
      family: {
        select: {
          name: true,
          users: {
            where: {
              emailVerifiedAt: { not: null },
            },
            select: {
              email: true,
            },
          },
        },
      },
    },
  });

  let sent = 0;
  let skipped = 0;
  const errors: string[] = [];

  for (const assignment of assignments) {
    const recipients = assignment.family.users.map((user) => user.email);
    if (recipients.length === 0) {
      skipped += 1;
      continue;
    }

    const weekLabel = `${format(assignment.startDate, "dd.MM.", {
      locale: de,
    })} - ${format(assignment.endDate, "dd.MM.yyyy", { locale: de })}`;

    const result = await sendAppEmail({
      to: recipients,
      subject: `Erinnerung: ${assignment.dutyType.name} diese Woche`,
      react: createElement(DutyReminderEmail, {
        familyName: assignment.family.name,
        dutyName: assignment.dutyType.name,
        weekLabel,
      }),
    });

    if (!result.success) {
      errors.push(`${assignment.family.name}: ${result.error}`);
      continue;
    }

    await prisma.dutyAssignment.update({
      where: { id: assignment.id },
      data: { reminderSentAt: new Date() },
    });
    sent += recipients.length;
  }

  revalidatePath("/dashboard/admin/dienste");
  return { success: true, sent, skipped, errors };
}
