import Link from "next/link";
import { addWeeks, format, getISOWeek, startOfDay, startOfWeek } from "date-fns";
import { de } from "date-fns/locale";
import { CalendarRange, 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: Promise<{ start?: string; weeks?: string }>;
}) {
  const session = await requireRole([UserRole.ADMIN, UserRole.SUPERADMIN]);
  if (!session.user.kitaId) {
    throw new Error("Kein Mandant zugeordnet.");
  }

  const resolvedSearchParams = await searchParams;
  const rangeStart = getRangeStart(resolvedSearchParams.start);
  const weekCount = getWeekCount(resolvedSearchParams.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="mx-auto max-w-[1280px] px-11 py-9 pb-16 max-[760px]:px-5">
      <header className="mb-7 flex items-end justify-between gap-8 max-[900px]:flex-col max-[900px]:items-start">
        <div>
          <p className="text-[11px] font-semibold uppercase text-[var(--accent-deep)] [letter-spacing:0.18em]">
            ADMIN · DIENSTPLAN
          </p>
          <h1 className="mt-2 text-[36px] font-normal leading-tight tracking-[-0.025em] text-[var(--ink)]">
            Dienste{" "}
            <em className="font-normal italic text-[var(--accent-deep)]">
              planen
            </em>
          </h1>
          <p className="mt-2 max-w-2xl text-[15px] leading-6 text-[var(--ink-soft)]">
            Plane Dienste pro Kalenderwoche und Haushalt. Jede Änderung wird
            direkt gespeichert.
          </p>
        </div>
        <div className="flex shrink-0 flex-wrap gap-2">
          <span className="inline-flex h-9 items-center rounded-full border border-[var(--hairline)] bg-[var(--surface)] px-3 text-[13px] font-semibold text-[var(--ink-soft)]">
            {dutyTypes.length} Diensttypen
          </span>
          <span className="inline-flex h-9 items-center rounded-full border border-[var(--hairline)] bg-[var(--surface)] px-3 text-[13px] font-semibold text-[var(--ink-soft)]">
            {families.length} Familien
          </span>
        </div>
      </header>

      <Card className="mb-5">
        <CardContent className="pt-[22px]">
          <form className="flex flex-wrap items-end gap-3">
            <div className="mr-auto min-w-64">
              <div className="flex items-center gap-2 text-base font-medium tracking-[-0.02em] text-[var(--ink)]">
                <CalendarRange className="h-4 w-4 text-[var(--accent-deep)] [stroke-width:1.7]" />
                Zeitraum
              </div>
              <p className="mt-1 text-[13.5px] text-[var(--ink-soft)]">
                {weeks[0].label} bis {weeks[weeks.length - 1].label}
              </p>
            </div>
            <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 w-28 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="ghost">
              <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 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-lg border border-dashed border-[var(--hairline)] bg-[var(--surface-2)] p-3 text-sm italic text-[var(--ink-faint)]">
                  Noch keine Diensttypen angelegt.
                </p>
              ) : (
                dutyTypes.map((dutyType) => (
                  <div
                    key={dutyType.id}
                    className="flex items-start justify-between gap-3 rounded-lg border border-[var(--hairline)] bg-[var(--surface-2)] p-3"
                  >
                    <div className="min-w-0">
                      <p className="font-medium text-[var(--ink)]">{dutyType.name}</p>
                      {dutyType.description && (
                        <p className="mt-1 line-clamp-2 text-xs text-[var(--ink-soft)]">
                          {dutyType.description}
                        </p>
                      )}
                    </div>
                    <form action={deleteDutyType}>
                      <input
                        type="hidden"
                        name="dutyTypeId"
                        value={dutyType.id}
                      />
                      <Button
                        type="submit"
                        variant="ghost"
                        size="icon"
                        className="text-[var(--danger)] hover:bg-[var(--danger-soft)] hover:text-[var(--danger)]"
                        aria-label={`${dutyType.name} löschen`}
                      >
                        <Trash2 className="h-4 w-4 [stroke-width:1.7]" />
                      </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");
}
