"use client";

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

import type { RentalBooking } from "@rental/shared";
import { addDays, bookingIntervalsOverlap, dayDiffInclusive, 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;
};

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,
  onClose,
  onSave,
  onDelete
}: {
  open: boolean;
  booking: BookingWithContext | null;
  existingBookings: BookingWithContext[];
  saving: boolean;
  deleting: 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;
    dayRate: number | null;
    totalPrice: number | null;
    allowConflict: boolean;
  }) => Promise<void>;
  onDelete: () => 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 [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 ?? "");
    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]);

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

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

  const shiftDates = (days: number) => {
    setStartDate((value) => addDays(value, days));
    setEndDate((value) => addDays(value, days));
  };

  return (
    <Modal
      open={open}
      onClose={onClose}
      title={booking ? `Rezerwacja: ${booking.customerName}` : "Szczegóły rezerwacji"}
      description={booking ? `${booking.categoryName} / ${booking.itemName}` : undefined}
      footer={
        <>
          <Button variant="danger" onClick={() => void onDelete()} disabled={deleting || saving}>
            {deleting ? "Usuwanie..." : "Usuń"}
          </Button>
          <div className="ml-auto flex flex-wrap gap-3">
            <Button variant="ghost" onClick={onClose}>
              Zamknij
            </Button>
            <Button
              type="submit"
              form="booking-edit-form"
              disabled={
                saving ||
                deleting ||
                !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,
                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>
            {conflicts.length > 0 ? <Badge tone="warning">Konflikt: {conflicts.length}</Badge> : null}
          </div>

          {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-3 sm:grid-cols-2">
            <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-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>
          </div>

          <div className="grid gap-3 sm:grid-cols-2">
            <label className="block space-y-1.5">
              <span className="text-sm font-medium text-ink">Godzina wydania</span>
              <Input type="time" value={startTime} onChange={(event) => setStartTime(event.target.value)} />
            </label>

            <label className="block space-y-1.5">
              <span className="text-sm font-medium text-ink">Godzina zwrotu</span>
              <Input type="time" value={endTime} onChange={(event) => setEndTime(event.target.value)} />
            </label>
          </div>

          <div className="flex flex-wrap gap-2">
            <Button variant="secondary" onClick={() => shiftDates(-7)}>
              -7 dni
            </Button>
            <Button variant="secondary" onClick={() => shiftDates(-1)}>
              -1 dzień
            </Button>
            <Button variant="secondary" onClick={() => shiftDates(1)}>
              +1 dzień
            </Button>
            <Button variant="secondary" onClick={() => shiftDates(7)}>
              +7 dni
            </Button>
          </div>

          <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 numer albo wyczyścić pole i pozwolić systemowi nadać nowy.</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>
  );
};
