"use client";

import { useEffect, useMemo, useState } from "react";

import type { BookingOperationsPlan, RentalBooking } from "@rental/shared";
import {
  BOOKING_OPERATION_TASK_TYPES,
  bookingIntervalsOverlap,
  dayDiffInclusive,
  normalizeBookingOperationsPlan,
  normalizeBookingTime
} from "@rental/shared";

import {
  bookingUsesManualTotalPrice,
  formatPriceInput,
  getAutomaticTotalPriceValue,
  parsePriceInput
} from "../../lib/booking-pricing";
import { cn } from "../../lib/cn";
import { Badge } from "../ui/badge";
import { Button } from "../ui/button";
import { Input, Textarea } from "../ui/input";
import { Modal } from "../ui/modal";

type BookingWithContext = RentalBooking & {
  itemName: string;
  categoryName: string;
  sourceBookingIds?: string[];
};

const framedInputClassName =
  "rounded-none border-0 bg-transparent px-0 py-0 text-sm text-ink shadow-none focus:border-transparent focus:ring-0";

const FramedField = ({
  label,
  className,
  children
}: {
  label: string;
  className?: string;
  children: React.ReactNode;
}) => (
  <label className={cn("relative block rounded-2xl border border-line bg-white px-3 pb-2 pt-3", className)}>
    <span className="absolute left-3 top-0 -translate-y-1/2 bg-[#fffdf8] px-1 text-[11px] font-semibold uppercase tracking-[0.14em] text-muted">
      {label}
    </span>
    {children}
  </label>
);

export const BookingDetailsModal = ({
  open,
  booking,
  existingBookings,
  saving,
  deleting,
  deletingProject,
  detaching,
  onClose,
  onSave,
  onDelete,
  onDeleteProject,
  onDetach
}: {
  open: boolean;
  booking: BookingWithContext | null;
  existingBookings: BookingWithContext[];
  saving: boolean;
  deleting: boolean;
  deletingProject: boolean;
  detaching: boolean;
  onClose: () => void;
  onSave: (payload: {
    equipmentItemId: string;
    customerName: string;
    orderNumber: string;
    projectNumber: string;
    projectName: string;
    notes: string;
    startDate: string;
    endDate: string;
    startTime: string | null;
    endTime: string | null;
    operationsPlan: BookingOperationsPlan | null;
    dayRate: number | null;
    totalPrice: number | null;
    allowConflict: boolean;
  }) => Promise<void>;
  onDelete: () => Promise<void>;
  onDeleteProject: () => Promise<void>;
  onDetach: () => Promise<void>;
}) => {
  const [equipmentItemId, setEquipmentItemId] = useState("");
  const [customerName, setCustomerName] = useState("");
  const [orderNumber, setOrderNumber] = useState("");
  const [projectNumber, setProjectNumber] = useState("");
  const [projectName, setProjectName] = useState("");
  const [notes, setNotes] = useState("");
  const [startDate, setStartDate] = useState("");
  const [endDate, setEndDate] = useState("");
  const [startTime, setStartTime] = useState("");
  const [endTime, setEndTime] = useState("");
  const [operationsPlan, setOperationsPlan] = useState<BookingOperationsPlan | null>(null);
  const [dayRate, setDayRate] = useState("");
  const [totalPrice, setTotalPrice] = useState("");
  const [totalPriceManual, setTotalPriceManual] = useState(false);

  useEffect(() => {
    if (!booking) {
      return;
    }

    setEquipmentItemId(booking.equipmentItemId);
    setCustomerName(booking.customerName);
    setOrderNumber(booking.orderNumber ?? "");
    setProjectNumber(booking.projectNumber ?? "");
    setProjectName(booking.projectName ?? "");
    setNotes(booking.notes ?? "");
    setStartDate(booking.startDate);
    setEndDate(booking.endDate);
    setStartTime(booking.startTime ?? "");
    setEndTime(booking.endTime ?? "");
    setOperationsPlan(
      normalizeBookingOperationsPlan(booking.operationsPlan, {
        startDate: booking.startDate,
        endDate: booking.endDate,
        startTime: booking.startTime,
        endTime: booking.endTime
      })
    );
    setDayRate(formatPriceInput(booking.dayRate));
    setTotalPrice(formatPriceInput(booking.totalPrice));
    setTotalPriceManual(bookingUsesManualTotalPrice(booking));
  }, [booking]);

  const normalizedStartTime = normalizeBookingTime(startTime);
  const normalizedEndTime = normalizeBookingTime(endTime);
  const parsedDayRate = parsePriceInput(dayRate);
  const parsedTotalPrice = parsePriceInput(totalPrice);
  const invalidSameDayTime =
    startDate === endDate && Boolean(normalizedStartTime && normalizedEndTime && normalizedStartTime >= normalizedEndTime);
  const invalidDayRate = dayRate.trim() !== "" && parsedDayRate === null;
  const invalidTotalPrice = totalPrice.trim() !== "" && parsedTotalPrice === null;
  const rentalDays = startDate && endDate && startDate <= endDate ? dayDiffInclusive(startDate, endDate) : 0;
  const automaticTotalPrice = startDate && endDate ? getAutomaticTotalPriceValue(startDate, endDate, dayRate) : null;
  const conflicts = useMemo(() => {
    if (!booking) {
      return [];
    }

    return existingBookings.filter(
      (existingBooking) =>
        existingBooking.id !== booking.id &&
        existingBooking.equipmentItemId === equipmentItemId &&
        bookingIntervalsOverlap(existingBooking, {
          startDate,
          endDate,
          startTime: normalizedStartTime,
          endTime: normalizedEndTime
        } as RentalBooking)
    );
  }, [booking, endDate, equipmentItemId, existingBookings, normalizedEndTime, normalizedStartTime, startDate]);
  const relationGroupCount = useMemo(() => {
    if (!booking) {
      return 1;
    }

    if (booking.sourceBookingIds && booking.sourceBookingIds.length > 1) {
      return booking.sourceBookingIds.length;
    }

    if (booking.relationGroupKey) {
      return existingBookings.filter(
        (existingBooking) =>
          existingBooking.relationGroupKey === booking.relationGroupKey &&
          existingBooking.startDate === booking.startDate &&
          existingBooking.endDate === booking.endDate &&
          (existingBooking.startTime ?? null) === (booking.startTime ?? null) &&
          (existingBooking.endTime ?? null) === (booking.endTime ?? null)
      ).length;
    }

    return existingBookings.filter(
      (existingBooking) =>
        existingBooking.projectNumber === booking.projectNumber &&
        existingBooking.projectName === booking.projectName &&
        existingBooking.startDate === booking.startDate &&
        existingBooking.endDate === booking.endDate &&
        (existingBooking.startTime ?? null) === (booking.startTime ?? null) &&
        (existingBooking.endTime ?? null) === (booking.endTime ?? null)
    ).length;
  }, [booking, existingBookings]);
  const canDetachFromProject = Boolean(booking?.projectNumber && relationGroupCount > 1);

  useEffect(() => {
    if (!booking || totalPriceManual) {
      return;
    }

    setTotalPrice(formatPriceInput(automaticTotalPrice));
  }, [automaticTotalPrice, booking, totalPriceManual]);

  return (
    <Modal
      open={open}
      onClose={onClose}
      title={booking ? `Rezerwacja: ${booking.customerName}` : "Szczegóły rezerwacji"}
      description={booking ? `${booking.categoryName} / ${booking.itemName}` : undefined}
      footer={
        <>
          <div className="flex flex-wrap gap-3">
            <Button variant="danger" onClick={() => void onDelete()} disabled={deleting || deletingProject || saving}>
              {deleting ? "Usuwanie..." : "Usuń tę relację"}
            </Button>
            {booking?.projectNumber ? (
              <Button variant="danger" onClick={() => void onDeleteProject()} disabled={deletingProject || deleting || saving}>
                {deletingProject ? "Usuwanie projektu..." : "Usuń cały projekt"}
              </Button>
            ) : null}
          </div>
          <div className="ml-auto flex flex-wrap gap-3">
            {canDetachFromProject ? (
              <Button variant="secondary" onClick={() => void onDetach()} disabled={detaching || deleting || deletingProject || saving}>
                {detaching ? "Rozdzielanie..." : "Rozdziel ten projekt"}
              </Button>
            ) : null}
            <Button variant="ghost" onClick={onClose}>
              Zamknij
            </Button>
            <Button
              type="submit"
              form="booking-edit-form"
              disabled={
                saving ||
                deleting ||
                deletingProject ||
                !customerName.trim() ||
                !equipmentItemId ||
                startDate > endDate ||
                invalidSameDayTime ||
                invalidDayRate ||
                invalidTotalPrice
              }
            >
              {saving ? "Zapisywanie..." : conflicts.length > 0 ? "Zapisz mimo konfliktu" : "Zapisz zmiany"}
            </Button>
          </div>
        </>
      }
    >
      {booking ? (
        <form
          className="space-y-3"
          id="booking-edit-form"
          onSubmit={(event) => {
            event.preventDefault();

            if (invalidSameDayTime || invalidDayRate || invalidTotalPrice) {
              return;
            }

            const submit = async (allowConflict: boolean) =>
              onSave({
                equipmentItemId,
                customerName,
                orderNumber,
                projectNumber,
                projectName,
                notes,
                startDate,
                endDate,
                startTime: normalizedStartTime,
                endTime: normalizedEndTime,
                operationsPlan:
                  operationsPlan
                    ? normalizeBookingOperationsPlan(operationsPlan, {
                        startDate,
                        endDate,
                        startTime: normalizedStartTime,
                        endTime: normalizedEndTime
                      })
                    : null,
                dayRate: parsedDayRate,
                totalPrice: totalPriceManual ? parsedTotalPrice : null,
                allowConflict
              });

            if (conflicts.length > 0) {
              const shouldAllowConflict = window.confirm(
                [
                  "Wykryto konflikt rezerwacji dla tego urządzenia.",
                  "Ustaw godzinę zwrotu poprzedniego tasku i godzinę wydania następnego, jeśli chcesz rozdzielić ten sam dzień.",
                  "",
                  "OK = zapisz mimo konfliktu",
                  "Anuluj = wróć do edycji"
                ].join("\n")
              );

              if (!shouldAllowConflict) {
                return;
              }

              void submit(true);
              return;
            }

            void submit(false);
          }}
        >
          <div className="flex flex-wrap gap-2">
            <Badge tone="accent">{booking.itemName}</Badge>
            <Badge tone="neutral">Utworzono: {booking.createdAt.slice(0, 10)}</Badge>
            {booking.projectNumber ? <Badge tone="neutral">Projekt: {booking.projectNumber}</Badge> : null}
            {relationGroupCount > 1 ? <Badge tone="success">Wspólny task: {relationGroupCount} urządzeń</Badge> : null}
            {conflicts.length > 0 ? <Badge tone="warning">Konflikt: {conflicts.length}</Badge> : null}
          </div>

          {canDetachFromProject ? (
            <div className="rounded-2xl bg-[#edf6ee] px-4 py-3 text-sm text-[#2f6940]">
              Ten blok jest wspólny dla {relationGroupCount} urządzeń. Użyj przycisku `Rozdziel ten projekt`, jeśli chcesz rozdzielić tylko ten blok wizualnie, bez zmiany numeru projektu.
            </div>
          ) : null}

          {conflicts.length > 0 ? (
            <div className="rounded-2xl bg-[#f6e1cf] px-4 py-3 text-sm text-[#8f5b1f]">
              Ten zakres nachodzi na inną rezerwację tego samego urządzenia. Możesz ustawić godziny albo zapisać konflikt świadomie.
            </div>
          ) : null}

          {invalidSameDayTime ? (
            <div className="rounded-2xl bg-[#f8d9d3] px-4 py-3 text-sm text-[#8d2f20]">
              Dla rezerwacji w tym samym dniu godzina zwrotu musi być późniejsza niż godzina wydania.
            </div>
          ) : null}

          <div className="grid gap-3 sm:grid-cols-3">
            <FramedField label="Liczba dni">
              <Input value={String(rentalDays)} disabled className={framedInputClassName} />
            </FramedField>

            <FramedField label="Stawka">
              <Input
                inputMode="decimal"
                value={dayRate}
                onChange={(event) => setDayRate(event.target.value)}
                placeholder="Np. 150,00"
                className={framedInputClassName}
              />
            </FramedField>

            <FramedField label="Cena całkowita">
              <Input
                inputMode="decimal"
                value={totalPrice}
                onChange={(event) => {
                  const nextValue = event.target.value;
                  setTotalPrice(nextValue);
                  setTotalPriceManual(nextValue.trim() !== "");
                }}
                placeholder="Wyczyść, aby liczyć automatycznie"
                className={framedInputClassName}
              />
            </FramedField>
          </div>

          {invalidDayRate || invalidTotalPrice ? (
            <div className="rounded-2xl bg-[#f8d9d3] px-4 py-3 text-sm text-[#8d2f20]">
              Stawka dzienna i cena całkowita muszą być liczbami dodatnimi, np. `150` albo `150,50`.
            </div>
          ) : null}

          {parsedDayRate !== null ? (
            <div className="rounded-2xl bg-[#edf6ee] px-4 py-3 text-sm text-[#2f6940]">
              {rentalDays} dni × {formatPriceInput(parsedDayRate)} = {formatPriceInput(automaticTotalPrice)}
            </div>
          ) : null}

          <FramedField label="Klient">
            <Input value={customerName} onChange={(event) => setCustomerName(event.target.value)} className={framedInputClassName} />
          </FramedField>

          <div className="grid gap-2 sm:grid-cols-[minmax(0,1fr)_150px_minmax(0,1fr)_150px]">
            <label className="flex items-center gap-3 rounded-2xl border border-line bg-white px-3 py-2.5">
              <span className="shrink-0 text-sm font-medium text-ink">Data od</span>
              <Input
                type="date"
                value={startDate}
                onChange={(event) => setStartDate(event.target.value)}
                className={cn(framedInputClassName, "min-w-0 text-right")}
              />
            </label>

            <label className="flex items-center gap-2 rounded-2xl border border-line bg-white px-3 py-2.5">
              <span className="shrink-0 text-xs font-medium text-ink">Wydanie</span>
              <Input
                type="time"
                value={startTime}
                onChange={(event) => setStartTime(event.target.value)}
                className={cn(framedInputClassName, "min-w-0 text-right")}
              />
            </label>

            <label className="flex items-center gap-3 rounded-2xl border border-line bg-white px-3 py-2.5">
              <span className="shrink-0 text-sm font-medium text-ink">Data do</span>
              <Input
                type="date"
                value={endDate}
                onChange={(event) => setEndDate(event.target.value)}
                className={cn(framedInputClassName, "min-w-0 text-right")}
              />
            </label>

            <label className="flex items-center gap-2 rounded-2xl border border-line bg-white px-3 py-2.5">
              <span className="shrink-0 text-xs font-medium text-ink">Zwrot</span>
              <Input
                type="time"
                value={endTime}
                onChange={(event) => setEndTime(event.target.value)}
                className={cn(framedInputClassName, "min-w-0 text-right")}
              />
            </label>
          </div>

          {operationsPlan ? (
            <div className="space-y-1.5 rounded-2xl border border-line bg-[#fbf8f2] px-3 py-2.5">
              <p className="text-xs font-semibold uppercase tracking-[0.14em] text-ink">Taski operacyjne</p>
              <div className="grid gap-1.5">
                {BOOKING_OPERATION_TASK_TYPES.map((task) => (
                  <div key={task.value} className="grid gap-2 sm:grid-cols-[130px_minmax(0,1fr)_115px] sm:items-center">
                    <div className="text-xs font-medium text-ink">{task.label}</div>
                    <Input
                      type="date"
                      value={operationsPlan[task.value].date ?? ""}
                      className="h-8 rounded-xl px-3 py-1 text-xs"
                      onChange={(event) =>
                        setOperationsPlan((current) =>
                          current
                            ? {
                                ...current,
                                [task.value]: { ...current[task.value], date: event.target.value || null }
                              }
                            : current
                        )
                      }
                    />
                    <Input
                      type="time"
                      value={operationsPlan[task.value].time ?? ""}
                      className="h-8 rounded-xl px-3 py-1 text-xs"
                      onChange={(event) =>
                        setOperationsPlan((current) =>
                          current
                            ? {
                                ...current,
                                [task.value]: { ...current[task.value], time: event.target.value || null }
                              }
                            : current
                        )
                      }
                    />
                  </div>
                ))}
              </div>
            </div>
          ) : null}

          <div className="grid gap-3 sm:grid-cols-3">
            <label className="block space-y-1.5">
              <span className="text-sm font-medium text-ink">Numer zamówienia</span>
              <Input
                value={orderNumber}
                onChange={(event) => setOrderNumber(event.target.value)}
                placeholder="Wyczyść pole, aby nadać nowy numer automatycznie"
              />
              <p className="text-xs text-muted">Możesz wpisać własny nr</p>
            </label>

            <label className="block space-y-1.5">
              <span className="text-sm font-medium text-ink">Numer projektu</span>
              <Input value={projectNumber} onChange={(event) => setProjectNumber(event.target.value)} />
            </label>

            <label className="block space-y-1.5">
              <span className="text-sm font-medium text-ink">Projekt</span>
              <Input value={projectName} onChange={(event) => setProjectName(event.target.value)} />
            </label>
          </div>

          <label className="block space-y-1.5">
            <span className="text-sm font-medium text-ink">Notatka</span>
            <Textarea value={notes} onChange={(event) => setNotes(event.target.value)} />
          </label>

          {conflicts.length > 0 ? (
            <div className="space-y-2 rounded-2xl border border-line bg-[#fff7ef] px-4 py-3">
              <p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Kolizje w osi czasu</p>
              {conflicts.slice(0, 5).map((conflict) => (
                <div key={conflict.id} className="text-sm text-ink">
                  {conflict.itemName} • {conflict.customerName} • {conflict.startDate}
                  {conflict.startTime ? ` ${conflict.startTime}` : ""}
                  {" - "}
                  {conflict.endDate}
                  {conflict.endTime ? ` ${conflict.endTime}` : ""}
                </div>
              ))}
            </div>
          ) : null}
        </form>
      ) : null}
    </Modal>
  );
};
