"use client";

import { useEffect, useMemo, useState } from "react";
import { bookingIntervalsOverlap, dayDiffInclusive, normalizeBookingTime, type EquipmentItem, type RentalBooking } from "@rental/shared";

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

type SelectionPayload = {
  equipmentItemIds: string[];
  startDate: string;
  endDate: string;
};

type ConflictBookingPreview = RentalBooking & {
  itemName: string;
  categoryName: string;
};

export const BookingAssignmentModal = ({
  open,
  selection,
  items,
  existingBookings,
  submitting,
  onClose,
  onSubmit
}: {
  open: boolean;
  selection: SelectionPayload | null;
  items: EquipmentItem[];
  existingBookings: ConflictBookingPreview[];
  submitting: boolean;
  onClose: () => void;
  onSubmit: (payload: {
    customerName: string;
    orderNumber: string;
    projectNumber: string;
    projectName: string;
    notes: string;
    startTime: string | null;
    endTime: string | null;
    dayRate: number | null;
    totalPrice: number | null;
    useSuggestedItemRates: boolean;
    allowConflict: boolean;
  }) => Promise<void>;
}) => {
  const [customerName, setCustomerName] = useState("");
  const [orderNumber, setOrderNumber] = useState("");
  const [projectNumber, setProjectNumber] = useState("");
  const [projectName, setProjectName] = useState("");
  const [notes, setNotes] = useState("");
  const [startTime, setStartTime] = useState("");
  const [endTime, setEndTime] = useState("");
  const [dayRate, setDayRate] = useState("");
  const [totalPrice, setTotalPrice] = useState("");
  const [totalPriceManual, setTotalPriceManual] = useState(false);

  const selectedItems = useMemo(() => {
    if (!selection) {
      return [];
    }

    const selectedItemIds = new Set(selection.equipmentItemIds);
    return items.filter((item) => selectedItemIds.has(item.id));
  }, [items, selection]);

  const rentalDays = selection ? dayDiffInclusive(selection.startDate, selection.endDate) : 0;
  const combinedSuggestedDayRate = selectedItems.reduce((sum, item) => sum + (item.suggestedDayRate ?? 0), 0);
  const hasAnySuggestedRate = selectedItems.some((item) => (item.suggestedDayRate ?? 0) > 0);
  const singleSelectedItem = selectedItems.length === 1 ? selectedItems[0] : null;

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

    setCustomerName("");
    setOrderNumber("");
    setProjectNumber("");
    setProjectName("");
    setNotes("");
    setStartTime("");
    setEndTime("");
    setDayRate(singleSelectedItem?.suggestedDayRate ? formatPriceInput(singleSelectedItem.suggestedDayRate) : "");
    setTotalPrice("");
    setTotalPriceManual(false);
  }, [open, singleSelectedItem]);

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

    const selectedItemIds = new Set(selection.equipmentItemIds);

    return existingBookings.filter(
      (booking) =>
        selectedItemIds.has(booking.equipmentItemId) &&
        bookingIntervalsOverlap(booking, {
          startDate: selection.startDate,
          endDate: selection.endDate,
          startTime: normalizedStartTime,
          endTime: normalizedEndTime
        } as RentalBooking)
    );
  }, [existingBookings, normalizedEndTime, normalizedStartTime, selection]);

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

    setTotalPrice(formatPriceInput(automaticTotalPrice));
  }, [automaticTotalPrice, open, selection, totalPriceManual]);

  const handleSubmit = async (event: React.FormEvent) => {
    event.preventDefault();

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

    const createPayload = {
      customerName,
      orderNumber,
      projectNumber,
      projectName,
      notes,
      startTime: normalizedStartTime,
      endTime: normalizedEndTime,
      dayRate: singleSelectedItem ? parsedDayRate : null,
      totalPrice: totalPriceManual ? parsedTotalPrice : null,
      useSuggestedItemRates: !singleSelectedItem && hasAnySuggestedRate,
      allowConflict: false
    };

    if (conflicts.length > 0) {
      const shouldAllowConflict = window.confirm(
        [
          "Wykryto konflikt rezerwacji dla wybranego sprzętu.",
          "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;
      }

      await onSubmit({
        ...createPayload,
        allowConflict: true
      });
      return;
    }

    await onSubmit(createPayload);
  };

  return (
    <Modal
      open={open}
      onClose={onClose}
      title="Nowa rezerwacja"
      description="Przypisz jednego klienta do zaznaczonego zakresu dni i urządzeń."
      footer={
        <>
          <Button variant="ghost" onClick={onClose}>
            Anuluj
          </Button>
          <Button
            onClick={() => void 0}
            type="submit"
            form="booking-create-form"
            disabled={submitting || !customerName.trim() || invalidSameDayTime || invalidDayRate || invalidTotalPrice}
          >
            {submitting ? "Zapisywanie..." : conflicts.length > 0 ? "Zapisz mimo konfliktu" : "Zapisz rezerwację"}
          </Button>
        </>
      }
    >
      <form className="space-y-4" id="booking-create-form" onSubmit={handleSubmit}>
        <div className="flex flex-wrap gap-2">
          <Badge tone="accent">{selection?.equipmentItemIds.length ?? 0} urządzeń</Badge>
          <Badge tone="neutral">
            {selection?.startDate} - {selection?.endDate}
          </Badge>
          {conflicts.length > 0 ? <Badge tone="warning">Konflikty: {conflicts.length}</Badge> : <Badge tone="success">Zakres wolny</Badge>}
        </div>

        {conflicts.length > 0 ? (
          <div className="rounded-2xl bg-[#f6e1cf] px-4 py-3 text-sm text-[#8f5b1f]">
            Wybrany zakres nachodzi na istniejące rezerwacje. Możesz ustawić godziny wydania i zwrotu albo zapisać konflikt świadomie.
          </div>
        ) : null}

        <label className="block space-y-2">
          <span className="text-sm font-medium text-ink">Klient</span>
          <Input value={customerName} onChange={(event) => setCustomerName(event.target.value)} placeholder="Np. Acme Events" />
        </label>

        <div className="grid gap-4 sm:grid-cols-2">
          <label className="block space-y-2">
            <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-2">
            <span className="text-sm font-medium text-ink">Godzina zwrotu</span>
            <Input type="time" value={endTime} onChange={(event) => setEndTime(event.target.value)} />
          </label>
        </div>

        {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-4 sm:grid-cols-3">
          <label className="block space-y-2">
            <span className="text-sm font-medium text-ink">Liczba dni</span>
            <Input value={String(rentalDays)} disabled />
          </label>

          {singleSelectedItem ? (
            <label className="block space-y-2">
              <span className="text-sm font-medium text-ink">Stawka dzienna</span>
              <Input
                inputMode="decimal"
                value={dayRate}
                onChange={(event) => setDayRate(event.target.value)}
                placeholder="Np. 150,00"
              />
            </label>
          ) : (
            <label className="block space-y-2">
              <span className="text-sm font-medium text-ink">Stawka dzienna łączna</span>
              <Input value={formatPriceInput(hasAnySuggestedRate ? combinedSuggestedDayRate : null)} disabled />
            </label>
          )}

          <label className="block space-y-2">
            <span className="text-sm font-medium text-ink">Cena całkowita</span>
            <Input
              inputMode="decimal"
              value={totalPrice}
              onChange={(event) => {
                const nextValue = event.target.value;
                setTotalPrice(nextValue);
                setTotalPriceManual(nextValue.trim() !== "");
              }}
              placeholder="Wyczyść, aby liczyć automatycznie"
            />
          </label>
        </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}

        {effectiveDayRate !== null ? (
          <div className="rounded-2xl bg-[#edf6ee] px-4 py-3 text-sm text-[#2f6940]">
            {rentalDays} dni × {formatPriceInput(effectiveDayRate)} = {formatPriceInput(automaticTotalPrice)}
          </div>
        ) : (
          <div className="rounded-2xl bg-[#f7f2ea] px-4 py-3 text-sm text-muted">
            Dodaj sugerowane stawki do sprzętu w panelu `Sprzęt`, aby system liczył wycenę automatycznie.
          </div>
        )}

        <div className="grid gap-4 sm:grid-cols-2">
          <label className="block space-y-2">
            <span className="text-sm font-medium text-ink">Numer zamówienia</span>
            <Input
              value={orderNumber}
              onChange={(event) => setOrderNumber(event.target.value)}
              placeholder="Puste pole = numer utworzy się sam"
            />
            <p className="text-xs text-muted">System nada automatycznie numer zamówienia, jeśli zostawisz to pole puste.</p>
          </label>

          <label className="block space-y-2">
            <span className="text-sm font-medium text-ink">Numer projektu</span>
            <Input
              value={projectNumber}
              onChange={(event) => setProjectNumber(event.target.value)}
              placeholder="Puste pole = numer utworzy się sam"
            />
            <p className="text-xs text-muted">Przy wielu urządzeniach cały task dostanie wspólny numer projektu.</p>
          </label>

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

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

        {selectedItems.length > 1 ? (
          <p className="text-xs text-muted">
            Dla wielu urządzeń system zapisze stawki sugerowane na poziomie każdego sprzętu, a ręczna cena całkowita zostanie rozdzielona proporcjonalnie.
          </p>
        ) : null}

        {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>
    </Modal>
  );
};
