import Link from "next/link";
import { addWeeks, format, getISOWeek, startOfDay, startOfWeek } from "date-fns";
import { de } from "date-fns/locale";
import { CalendarRange, ClipboardList, Plus, Trash2 } from "lucide-react";
import { UserRole } from "@prisma/client";

import { Button } from "@/components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { requireRole } from "@/lib/auth-utils";
import { prisma } from "@/lib/prisma";
import { createDutyType, deleteDutyType } from "./actions";
import {
  DutyPlanner,
  type DutyPlanAssignmentDto,
  type DutyPlanDutyTypeDto,
  type DutyPlanFamilyDto,
  type DutyPlanWeekDto,
} from "./duty-planner";

export const metadata = { title: "Dienstplan · Kita-Planer" };

const DEFAULT_WEEK_COUNT = 12;
const MAX_WEEK_COUNT = 104;

export default async function DienstePage({
  searchParams,
}: {
  searchParams: { start?: string; weeks?: string };
}) {
  const session = await requireRole([UserRole.ADMIN, UserRole.SUPERADMIN]);
  if (!session.user.kitaId) {
    throw new Error("Kein Mandant zugeordnet.");
  }

  const rangeStart = getRangeStart(searchParams.start);
  const weekCount = getWeekCount(searchParams.weeks);
  const weeks = buildWeeks(rangeStart, weekCount);
  const rangeEnd = startOfDay(new Date(weeks[weeks.length - 1].endDate));

  const [dutyTypes, families, assignments] = await Promise.all([
    prisma.dutyType.findMany({
      where: { kitaId: session.user.kitaId },
      select: {
        id: true,
        name: true,
        description: true,
      },
      orderBy: { name: "asc" },
    }),
    prisma.family.findMany({
      where: { kitaId: session.user.kitaId },
      select: {
        id: true,
        name: true,
      },
      orderBy: { name: "asc" },
    }),
    prisma.dutyAssignment.findMany({
      where: {
        kitaId: session.user.kitaId,
        startDate: {
          gte: rangeStart,
          lte: rangeEnd,
        },
      },
      select: {
        id: true,
        dutyTypeId: true,
        familyId: true,
        startDate: true,
      },
    }),
  ]);

  const dutyTypeDtos: DutyPlanDutyTypeDto[] = dutyTypes;
  const familyDtos: DutyPlanFamilyDto[] = families;
  const assignmentDtos: DutyPlanAssignmentDto[] = assignments.map((assignment) => ({
    id: assignment.id,
    dutyTypeId: assignment.dutyTypeId,
    familyId: assignment.familyId,
    startDate: toDateKey(assignment.startDate),
  }));

  return (
    <div className="space-y-6 p-6">
      <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
        <div>
          <div className="flex items-center gap-2 text-sm font-medium text-muted-foreground">
            <ClipboardList className="h-4 w-4" />
            Admin
          </div>
          <h1 className="mt-2 text-2xl font-bold tracking-tight">
            Dienstplan-Manager
          </h1>
          <p className="mt-1 max-w-2xl text-sm text-muted-foreground">
            Plane Dienste pro Kalenderwoche und Haushalt. Jede Änderung wird
            direkt gespeichert.
          </p>
        </div>

        <Card className="w-full lg:max-w-xl">
          <CardHeader className="pb-3">
            <CardTitle className="flex items-center gap-2 text-base">
              <CalendarRange className="h-4 w-4" />
              Zeitraum
            </CardTitle>
            <CardDescription>
              Du kannst beliebig weit voraus planen, jeweils in handlichen
              Ausschnitten.
            </CardDescription>
          </CardHeader>
          <CardContent>
            <form className="flex flex-col gap-3 sm:flex-row sm:items-end">
              <div className="grid gap-1.5">
                <Label htmlFor="start">Startwoche</Label>
                <Input
                  id="start"
                  name="start"
                  type="date"
                  defaultValue={toDateInputValue(rangeStart)}
                />
              </div>
              <div className="grid gap-1.5">
                <Label htmlFor="weeks">Wochen</Label>
                <Input
                  id="weeks"
                  name="weeks"
                  type="number"
                  min={1}
                  max={MAX_WEEK_COUNT}
                  defaultValue={weekCount}
                />
              </div>
              <Button type="submit">Anzeigen</Button>
              <Button asChild type="button" variant="outline">
                <Link
                  href={`/dashboard/admin/dienste?start=${toDateInputValue(
                    rangeStart,
                  )}&weeks=${Math.min(weekCount + 12, MAX_WEEK_COUNT)}`}
                >
                  Weitere Wochen laden
                </Link>
              </Button>
            </form>
          </CardContent>
        </Card>
      </div>

      <div className="grid gap-6 xl:grid-cols-[340px_1fr]">
        <Card>
          <CardHeader>
            <CardTitle className="text-base">Diensttypen</CardTitle>
            <CardDescription>
              Beispiele sind Wäschedienst, Einkauf oder Gartendienst.
            </CardDescription>
          </CardHeader>
          <CardContent className="space-y-5">
            <form action={createDutyType} className="space-y-3">
              <div className="grid gap-1.5">
                <Label htmlFor="name">Name</Label>
                <Input id="name" name="name" placeholder="Wäschedienst" />
              </div>
              <div className="grid gap-1.5">
                <Label htmlFor="description">Beschreibung</Label>
                <Textarea
                  id="description"
                  name="description"
                  placeholder="Kurz beschreiben, was zu tun ist."
                  rows={3}
                />
              </div>
              <Button type="submit" size="sm">
                <Plus className="h-4 w-4" />
                Diensttyp anlegen
              </Button>
            </form>

            <div className="space-y-2">
              {dutyTypes.length === 0 ? (
                <p className="rounded-md bg-muted p-3 text-sm text-muted-foreground">
                  Noch keine Diensttypen angelegt.
                </p>
              ) : (
                dutyTypes.map((dutyType) => (
                  <div
                    key={dutyType.id}
                    className="flex items-start justify-between gap-3 rounded-md border p-3"
                  >
                    <div className="min-w-0">
                      <p className="font-medium">{dutyType.name}</p>
                      {dutyType.description && (
                        <p className="mt-1 line-clamp-2 text-xs text-muted-foreground">
                          {dutyType.description}
                        </p>
                      )}
                    </div>
                    <form action={deleteDutyType}>
                      <input
                        type="hidden"
                        name="dutyTypeId"
                        value={dutyType.id}
                      />
                      <Button
                        type="submit"
                        variant="ghost"
                        size="icon"
                        aria-label={`${dutyType.name} löschen`}
                      >
                        <Trash2 className="h-4 w-4" />
                      </Button>
                    </form>
                  </div>
                ))
              )}
            </div>
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle className="text-base">Planung</CardTitle>
            <CardDescription>
              {weeks[0].label} bis {weeks[weeks.length - 1].label}
            </CardDescription>
          </CardHeader>
          <CardContent>
            <DutyPlanner
              weeks={weeks}
              dutyTypes={dutyTypeDtos}
              families={familyDtos}
              assignments={assignmentDtos}
            />
          </CardContent>
        </Card>
      </div>
    </div>
  );
}

function getRangeStart(value: string | undefined) {
  const parsed = value ? new Date(value) : new Date();
  const safeDate = Number.isNaN(parsed.getTime()) ? new Date() : parsed;
  return startOfDay(startOfWeek(safeDate, { weekStartsOn: 1 }));
}

function getWeekCount(value: string | undefined) {
  const parsed = Number(value);
  if (!Number.isFinite(parsed)) return DEFAULT_WEEK_COUNT;
  return Math.min(Math.max(Math.trunc(parsed), 1), MAX_WEEK_COUNT);
}

function buildWeeks(start: Date, count: number): DutyPlanWeekDto[] {
  return Array.from({ length: count }, (_, index) => {
    const weekStart = addWeeks(start, index);
    const weekEnd = addWeeks(start, index);
    weekEnd.setDate(weekStart.getDate() + 6);

    return {
      key: toDateKey(weekStart),
      label: `KW ${getISOWeek(weekStart)}: ${format(weekStart, "dd.MM.", {
        locale: de,
      })} - ${format(weekEnd, "dd.MM.", { locale: de })}`,
      startDate: toDateKey(weekStart),
      endDate: toDateKey(weekEnd),
    };
  });
}

function toDateKey(date: Date) {
  return format(date, "yyyy-MM-dd");
}

function toDateInputValue(date: Date) {
  return format(date, "yyyy-MM-dd");
}
