"use client";

import { useEffect, useRef, useState, type PointerEvent as ReactPointerEvent } from "react";
import { ChevronDown, ChevronRight, LaptopMinimalCheck } from "lucide-react";

import type { RentalBooking, TimelineGroup } from "@rental/shared";
import {
  addDays,
  bookingConflictOnDay,
  bookingIntervalsOverlap,
  getBookingEndStamp,
  getBookingStartStamp
} from "@rental/shared";

import { Badge } from "../ui/badge";
import { cn } from "../../lib/cn";

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

type SelectionDraft = {
  startRow: number;
  endRow: number;
  startDay: number;
  endDay: number;
};

type MoveBookingInteractionDraft = {
  kind: "move";
  booking: BookingWithContext;
  equipmentItemId: string;
  startDate: string;
  endDate: string;
  pointerStartDay: number;
};

type ResizeEndBookingInteractionDraft = {
  kind: "resize-end";
  booking: BookingWithContext;
  equipmentItemId: string;
  startDate: string;
  endDate: string;
  pointerStartDay: number;
};

type ResizeVerticalBookingInteractionDraft = {
  kind: "resize-vertical";
  booking: BookingWithContext;
  startRow: number;
  endRow: number;
  initialStartRow: number;
  initialEndRow: number;
  direction: "top" | "bottom";
};

type BookingInteractionDraft =
  | MoveBookingInteractionDraft
  | ResizeEndBookingInteractionDraft
  | ResizeVerticalBookingInteractionDraft;

type BarPointerIntent =
  | {
      kind: "move";
    }
  | {
      kind: "resize-end";
    }
  | {
      kind: "resize-vertical";
      direction: "top" | "bottom";
    };

type BookingPreviewDraft = {
  kind: "move" | "resize-end" | "resize-vertical";
  booking: BookingWithContext;
  equipmentItemId: string;
  startDate: string;
  endDate: string;
};

type VisibleItem = TimelineGroup["items"][number];
type RowBookingLayout = ReturnType<typeof buildRowBookingLayout>;

type RowRenderState = {
  item: VisibleItem;
  rowIndex: number;
  previewOnRow: boolean;
  renderedBookings: BookingWithContext[];
  rowLayout: RowBookingLayout;
  hasStackedLanes: boolean;
  bookingBarHeight: number;
  bookingTopOffset: number;
  laneStep: number;
  rowMinHeight: number;
};

type MergedBookingBlock = {
  blockId: string;
  topRowIndex: number;
  bottomRowIndex: number;
  representative: BookingWithContext;
  bookingIds: string[];
  equipmentItemIds: string[];
  left: number;
  width: number;
  top: number;
  height: number;
};

const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);

const dayOffset = (from: string, to: string) => {
  const start = new Date(`${from}T12:00:00.000Z`).getTime();
  const end = new Date(`${to}T12:00:00.000Z`).getTime();
  return Math.round((end - start) / 86_400_000);
};

const isDateInsideBooking = (date: string, booking: RentalBooking) => booking.startDate <= date && booking.endDate >= date;

const normalizeSelection = (selection: SelectionDraft) => ({
  startRow: Math.min(selection.startRow, selection.endRow),
  endRow: Math.max(selection.startRow, selection.endRow),
  startDay: Math.min(selection.startDay, selection.endDay),
  endDay: Math.max(selection.startDay, selection.endDay)
});

const getBookingPreviewDraft = (
  booking: BookingWithContext,
  interaction: BookingInteractionDraft | null
): BookingPreviewDraft | null => {
  if (!interaction || interaction.booking.id !== booking.id) {
    return null;
  }

  if (interaction.kind === "resize-vertical") {
    return {
      kind: interaction.kind,
      booking,
      equipmentItemId: booking.equipmentItemId,
      startDate: booking.startDate,
      endDate: booking.endDate
    };
  }

  return {
    kind: interaction.kind,
    booking,
    equipmentItemId: interaction.equipmentItemId,
    startDate: interaction.startDate,
    endDate: interaction.endDate
  };
};

const compareBookingsByStart = (left: BookingWithContext, right: BookingWithContext) =>
  getBookingStartStamp(left) - getBookingStartStamp(right) || getBookingEndStamp(left) - getBookingEndStamp(right);

const buildRowBookingLayout = (bookings: BookingWithContext[]) => {
  const sortedBookings = [...bookings].sort(compareBookingsByStart);
  const laneByBookingId = new Map<string, number>();
  const laneEndStamps: number[] = [];
  const conflictDays = new Set<string>();
  const conflictBookingIds = new Set<string>();
  let maxLane = 0;

  for (const booking of sortedBookings) {
    const bookingStart = getBookingStartStamp(booking);
    const bookingEnd = getBookingEndStamp(booking);
    let laneIndex = laneEndStamps.findIndex((laneEndStamp) => laneEndStamp <= bookingStart);

    if (laneIndex === -1) {
      laneIndex = laneEndStamps.length;
      laneEndStamps.push(bookingEnd);
    } else {
      laneEndStamps[laneIndex] = bookingEnd;
    }

    laneByBookingId.set(booking.id, laneIndex);
    maxLane = Math.max(maxLane, laneIndex);
  }

  for (let leftIndex = 0; leftIndex < sortedBookings.length; leftIndex += 1) {
    const leftBooking = sortedBookings[leftIndex];

    if (!leftBooking) {
      continue;
    }

    for (let rightIndex = leftIndex + 1; rightIndex < sortedBookings.length; rightIndex += 1) {
      const rightBooking = sortedBookings[rightIndex];

      if (!rightBooking) {
        continue;
      }

      if (getBookingStartStamp(rightBooking) >= getBookingEndStamp(leftBooking)) {
        break;
      }

      if (!bookingIntervalsOverlap(leftBooking, rightBooking)) {
        continue;
      }

      conflictBookingIds.add(leftBooking.id);
      conflictBookingIds.add(rightBooking.id);

      let dayCursor = leftBooking.startDate > rightBooking.startDate ? leftBooking.startDate : rightBooking.startDate;
      const dayEnd = leftBooking.endDate < rightBooking.endDate ? leftBooking.endDate : rightBooking.endDate;

      while (dayCursor <= dayEnd) {
        if (bookingConflictOnDay(leftBooking, rightBooking, dayCursor)) {
          conflictDays.add(dayCursor);
        }

        dayCursor = addDays(dayCursor, 1);
      }
    }
  }

  return {
    laneByBookingId,
    maxLane,
    conflictDays,
    conflictBookingIds
  };
};

const getBookingMergeSignature = (booking: BookingWithContext) => {
  const normalizedProjectName = booking.projectName?.trim().toLowerCase() ?? "";

  if (!normalizedProjectName) {
    return `booking::${booking.id}`;
  }

  return [
    "project",
    normalizedProjectName,
    booking.startDate,
    booking.endDate,
    booking.startTime ?? "",
    booking.endTime ?? ""
  ].join("::");
};

const buildMergedBookingBlocks = ({
  dayCount,
  effectiveDayWidth,
  firstDay,
  labelWidth,
  rowStates
}: {
  dayCount: number;
  effectiveDayWidth: number;
  firstDay: string;
  labelWidth: number;
  rowStates: RowRenderState[];
}) => {
  const candidatesByRow = rowStates.map((rowState) => {
    const rowCandidates = new Map<
      string,
      {
        booking: BookingWithContext;
        endIndex: number;
        signature: string;
        startIndex: number;
      }
    >();

    if (rowState.hasStackedLanes) {
      return rowCandidates;
    }

    for (const booking of rowState.renderedBookings) {
      const laneIndex = rowState.rowLayout.laneByBookingId.get(booking.id) ?? 0;

      if (laneIndex !== 0 || rowState.rowLayout.conflictBookingIds.has(booking.id)) {
        continue;
      }

      const startIndex = Math.max(0, dayOffset(firstDay, booking.startDate));
      const endIndex = Math.min(dayCount - 1, dayOffset(firstDay, booking.endDate));

      if (endIndex < 0 || startIndex > dayCount - 1) {
        continue;
      }

      const signature = getBookingMergeSignature(booking);

      if (!rowCandidates.has(signature)) {
        rowCandidates.set(signature, {
          booking,
          endIndex,
          signature,
          startIndex
        });
      }
    }

    return rowCandidates;
  });

  const mergedBlocksByTopRowIndex = new Map<number, MergedBookingBlock[]>();
  const mergedBlockByBookingId = new Map<string, MergedBookingBlock>();
  const consumedBookingIds = new Set<string>();

  for (const [rowIndex, rowCandidates] of candidatesByRow.entries()) {
    for (const candidate of rowCandidates.values()) {
      if (consumedBookingIds.has(candidate.booking.id)) {
        continue;
      }

      let bottomRowIndex = rowIndex;
      const bookingIds = [candidate.booking.id];

      for (let nextRowIndex = rowIndex + 1; nextRowIndex < candidatesByRow.length; nextRowIndex += 1) {
        const nextCandidate = candidatesByRow[nextRowIndex]?.get(candidate.signature);

        if (!nextCandidate || consumedBookingIds.has(nextCandidate.booking.id)) {
          break;
        }

        bottomRowIndex = nextRowIndex;
        bookingIds.push(nextCandidate.booking.id);
      }

      if (bottomRowIndex === rowIndex) {
        continue;
      }

      for (const bookingId of bookingIds) {
        consumedBookingIds.add(bookingId);
      }

      const topOffset = rowStates[rowIndex]?.bookingTopOffset ?? 1;
      const spannedHeight = rowStates
        .slice(rowIndex, bottomRowIndex + 1)
        .reduce((height, rowState) => height + rowState.rowMinHeight, 0);
      const block: MergedBookingBlock = {
        blockId: `${candidate.signature}-${rowIndex}`,
        topRowIndex: rowIndex,
        bottomRowIndex,
        representative: candidate.booking,
        bookingIds,
        equipmentItemIds: rowStates.slice(rowIndex, bottomRowIndex + 1).map((rowState) => rowState.item.id),
        left: labelWidth + candidate.startIndex * effectiveDayWidth + 3,
        width: Math.max((candidate.endIndex - candidate.startIndex + 1) * effectiveDayWidth - 6, 18),
        top: topOffset,
        height: Math.max(spannedHeight - topOffset * 2, 12)
      };

      for (const bookingId of bookingIds) {
        mergedBlockByBookingId.set(bookingId, block);
      }

      const blocks = mergedBlocksByTopRowIndex.get(rowIndex) ?? [];
      blocks.push(block);
      mergedBlocksByTopRowIndex.set(rowIndex, blocks);
    }
  }

  return {
    mergedBlockByBookingId,
    mergedBlocksByTopRowIndex
  };
};

export const TimelineGrid = ({
  bookingBarHeight,
  dayWidth,
  days,
  groups,
  collapsedGroups,
  mobileMode,
  rowHeight,
  selectionEnabled,
  interactionsLocked = false,
  onToggleGroup,
  onSelectionComplete,
  onRequestFutureRange,
  onBookingClick,
  onBookingQuickUpdate,
  onBookingScopeUpdate
}: {
  bookingBarHeight: number;
  dayWidth: number;
  days: string[];
  groups: TimelineGroup[];
  collapsedGroups: string[];
  mobileMode: boolean;
  rowHeight: number;
  selectionEnabled: boolean;
  interactionsLocked?: boolean;
  onToggleGroup: (categoryId: string) => void;
  onSelectionComplete: (selection: { equipmentItemIds: string[]; startDate: string; endDate: string }) => void;
  onRequestFutureRange?: () => void;
  onBookingClick: (booking: BookingWithContext) => void;
  onBookingQuickUpdate: (
    booking: BookingWithContext,
    payload: { equipmentItemId: string; startDate: string; endDate: string }
  ) => Promise<void>;
  onBookingScopeUpdate: (booking: BookingWithContext, payload: { equipmentItemIds: string[] }) => Promise<void>;
}) => {
  const [selectionDraft, setSelectionDraft] = useState<SelectionDraft | null>(null);
  const [bookingInteraction, setBookingInteraction] = useState<BookingInteractionDraft | null>(null);
  const [scrollerWidth, setScrollerWidth] = useState(0);

  const scrollerRef = useRef<HTMLDivElement | null>(null);
  const rowElementsRef = useRef(new Map<string, HTMLDivElement>());
  const selectionDraftRef = useRef<SelectionDraft | null>(null);
  const bookingInteractionRef = useRef<BookingInteractionDraft | null>(null);
  const visibleItemsRef = useRef<VisibleItem[]>([]);
  const daysRef = useRef(days);
  const lastForwardRangeRequestRef = useRef<string | null>(null);

  const visibleItems: VisibleItem[] = [];

  for (const group of groups) {
    if (collapsedGroups.includes(group.categoryId)) {
      continue;
    }

    visibleItems.push(...group.items);
  }

  useEffect(() => {
    selectionDraftRef.current = selectionDraft;
  }, [selectionDraft]);

  useEffect(() => {
    bookingInteractionRef.current = bookingInteraction;
  }, [bookingInteraction]);

  useEffect(() => {
    visibleItemsRef.current = visibleItems;
  }, [visibleItems]);

  useEffect(() => {
    daysRef.current = days;
  }, [days]);

  useEffect(() => {
    const lastDay = days[days.length - 1] ?? null;

    if (!lastDay) {
      lastForwardRangeRequestRef.current = null;
      return;
    }

    if (lastForwardRangeRequestRef.current && lastForwardRangeRequestRef.current < lastDay) {
      lastForwardRangeRequestRef.current = null;
    }
  }, [days]);

  useEffect(() => {
    const scroller = scrollerRef.current;

    if (!scroller || typeof ResizeObserver === "undefined") {
      return;
    }

    const updateWidth = () => setScrollerWidth(scroller.clientWidth);
    updateWidth();

    const observer = new ResizeObserver(() => updateWidth());
    observer.observe(scroller);

    return () => observer.disconnect();
  }, []);

  const labelWidth = mobileMode ? 168 : 176;
  const fittedDesktopDayWidth =
    !mobileMode && scrollerWidth > labelWidth ? Math.floor((scrollerWidth - labelWidth) / 30) : 34;
  const effectiveDayWidth = mobileMode ? dayWidth : clamp(Math.min(dayWidth, fittedDesktopDayWidth), 26, 64);
  const effectiveRowHeight = rowHeight;
  const stackedBookingBarHeight = clamp(Math.min(bookingBarHeight, effectiveRowHeight - 6), 12, effectiveRowHeight - 6);
  const singleBookingBarHeight = clamp(effectiveRowHeight - 2, 12, effectiveRowHeight - 2);
  const stackedBookingTopOffset = Math.max(Math.floor((effectiveRowHeight - stackedBookingBarHeight) / 2), 1);
  const singleBookingTopOffset = Math.max(Math.floor((effectiveRowHeight - singleBookingBarHeight) / 2), 1);
  const gridTemplateColumns = `${labelWidth}px repeat(${days.length}, ${effectiveDayWidth}px)`;
  const today = new Date().toISOString().slice(0, 10);
  const firstDay = days[0];
  const lastDay = days[days.length - 1];
  const scrollerMaxHeight = mobileMode ? "min(68dvh, 760px)" : "min(74dvh, 980px)";
  const verticalResizeHandleSize = mobileMode ? 10 : 8;
  const horizontalResizeHandleSize = mobileMode ? 16 : 12;

  if (!firstDay) {
    return null;
  }

  const setRowElement = (itemId: string, element: HTMLDivElement | null) => {
    if (element) {
      rowElementsRef.current.set(itemId, element);
      return;
    }

    rowElementsRef.current.delete(itemId);
  };

  const updateSelectionTarget = (target: { rowIndex: number; dayIndex: number }) => {
    setSelectionDraft((draft) =>
      draft
        ? {
            ...draft,
            endRow: target.rowIndex,
            endDay: target.dayIndex
          }
        : draft
    );
  };

  const autoScrollScroller = (clientX: number, clientY: number) => {
    const scroller = scrollerRef.current;

    if (!scroller) {
      return;
    }

    const rect = scroller.getBoundingClientRect();
    const edge = 56;

    if (clientY < rect.top + edge) {
      scroller.scrollTop -= Math.ceil((rect.top + edge - clientY) / 8);
    } else if (clientY > rect.bottom - edge) {
      scroller.scrollTop += Math.ceil((clientY - (rect.bottom - edge)) / 8);
    }

    if (clientX < rect.left + edge) {
      scroller.scrollLeft -= Math.ceil((rect.left + edge - clientX) / 8);
    } else if (clientX > rect.right - edge) {
      scroller.scrollLeft += Math.ceil((clientX - (rect.right - edge)) / 8);
    }
  };

  const getDayIndexFromClientX = (clientX: number) => {
    const scroller = scrollerRef.current;
    const currentDays = daysRef.current;

    if (!scroller || currentDays.length === 0) {
      return null;
    }

    const rect = scroller.getBoundingClientRect();
    const contentX = clientX - rect.left + scroller.scrollLeft - labelWidth;

    return clamp(Math.floor(contentX / effectiveDayWidth), 0, currentDays.length - 1);
  };

  const getRowIndexFromClientY = (clientY: number) => {
    const currentVisibleItems = visibleItemsRef.current;

    if (currentVisibleItems.length === 0) {
      return null;
    }

    let closestIndex = 0;
    let closestDistance = Number.POSITIVE_INFINITY;

    for (const [index, item] of currentVisibleItems.entries()) {
      const rowElement = rowElementsRef.current.get(item.id);

      if (!rowElement) {
        continue;
      }

      const rect = rowElement.getBoundingClientRect();

      if (clientY >= rect.top && clientY <= rect.bottom) {
        return index;
      }

      const distance = clientY < rect.top ? rect.top - clientY : clientY - rect.bottom;

      if (distance < closestDistance) {
        closestDistance = distance;
        closestIndex = index;
      }
    }

    return closestIndex;
  };

  const resolveGridTarget = (clientX: number, clientY: number) => {
    const dayIndex = getDayIndexFromClientX(clientX);
    const rowIndex = getRowIndexFromClientY(clientY);

    if (dayIndex === null || rowIndex === null) {
      return null;
    }

    return { dayIndex, rowIndex };
  };

  const resolveBarPointerIntent = (
    event: ReactPointerEvent<HTMLElement>,
    options?: {
      allowResizeEnd?: boolean;
    }
  ): BarPointerIntent => {
    const rect = event.currentTarget.getBoundingClientRect();
    const offsetY = event.clientY - rect.top;
    const remainingRight = rect.right - event.clientX;

    if (offsetY <= verticalResizeHandleSize) {
      return {
        kind: "resize-vertical",
        direction: "top"
      };
    }

    if (rect.height - offsetY <= verticalResizeHandleSize) {
      return {
        kind: "resize-vertical",
        direction: "bottom"
      };
    }

    if (options?.allowResizeEnd && remainingRight <= horizontalResizeHandleSize) {
      return {
        kind: "resize-end"
      };
    }

    return {
      kind: "move"
    };
  };

  const hasActivePointerInteraction = Boolean(selectionDraft || bookingInteraction);

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

    const handlePointerMove = (event: PointerEvent) => {
      autoScrollScroller(event.clientX, event.clientY);

      const target = resolveGridTarget(event.clientX, event.clientY);

      if (!target) {
        return;
      }

      const currentSelection = selectionDraftRef.current;

      if (currentSelection) {
        updateSelectionTarget(target);
        return;
      }

      const currentBookingInteraction = bookingInteractionRef.current;

      if (!currentBookingInteraction) {
        return;
      }

      if (currentBookingInteraction.kind === "move") {
        const nextItem = visibleItemsRef.current[target.rowIndex];

        if (!nextItem) {
          return;
        }

        const dayDelta = target.dayIndex - currentBookingInteraction.pointerStartDay;

        setBookingInteraction((draft) =>
          draft && draft.kind === "move"
            ? {
                ...draft,
                equipmentItemId: nextItem.id,
                startDate: addDays(draft.booking.startDate, dayDelta),
                endDate: addDays(draft.booking.endDate, dayDelta)
              }
            : draft
        );
        return;
      }

      if (currentBookingInteraction.kind === "resize-vertical") {
        setBookingInteraction((draft) =>
          draft && draft.kind === "resize-vertical"
            ? {
                ...draft,
                startRow:
                  draft.direction === "top"
                    ? Math.min(target.rowIndex, draft.endRow)
                    : draft.startRow,
                endRow:
                  draft.direction === "bottom"
                    ? Math.max(target.rowIndex, draft.startRow)
                    : draft.endRow
              }
            : draft
        );
        return;
      }

      const hoveredDay = daysRef.current[target.dayIndex] ?? currentBookingInteraction.endDate;
      const nextEndDate = hoveredDay < currentBookingInteraction.booking.startDate
        ? currentBookingInteraction.booking.startDate
        : hoveredDay;

      setBookingInteraction((draft) =>
        draft && draft.kind === "resize-end"
          ? {
              ...draft,
              endDate: nextEndDate
            }
          : draft
      );
    };

    const handlePointerUp = () => {
      const currentSelection = selectionDraftRef.current;

      if (currentSelection) {
        const normalized = normalizeSelection(currentSelection);
        const equipmentItemIds = visibleItemsRef.current
          .slice(normalized.startRow, normalized.endRow + 1)
          .map((item) => item.id);

        setSelectionDraft(null);

        if (equipmentItemIds.length === 0) {
          return;
        }

        onSelectionComplete({
          equipmentItemIds,
          startDate: daysRef.current[normalized.startDay] ?? firstDay,
          endDate: daysRef.current[normalized.endDay] ?? firstDay
        });
        return;
      }

      const currentBookingInteraction = bookingInteractionRef.current;

      if (!currentBookingInteraction) {
        return;
      }

      setBookingInteraction(null);

      if (currentBookingInteraction.kind === "resize-vertical") {
        const startRow = Math.min(
          currentBookingInteraction.startRow,
          currentBookingInteraction.endRow
        );
        const endRow = Math.max(
          currentBookingInteraction.startRow,
          currentBookingInteraction.endRow
        );
        const initialStartRow = currentBookingInteraction.initialStartRow;
        const initialEndRow = currentBookingInteraction.initialEndRow;

        if (startRow === initialStartRow && endRow === initialEndRow) {
          return;
        }

        const equipmentItemIds = visibleItemsRef.current.slice(startRow, endRow + 1).map((item) => item.id);

        if (equipmentItemIds.length === 0) {
          return;
        }

        void onBookingScopeUpdate(currentBookingInteraction.booking, { equipmentItemIds });
        return;
      }

      const changed =
        currentBookingInteraction.equipmentItemId !== currentBookingInteraction.booking.equipmentItemId ||
        currentBookingInteraction.startDate !== currentBookingInteraction.booking.startDate ||
        currentBookingInteraction.endDate !== currentBookingInteraction.booking.endDate;

      if (!changed) {
        if (currentBookingInteraction.kind === "move") {
          onBookingClick(currentBookingInteraction.booking);
        }

        return;
      }

      void onBookingQuickUpdate(currentBookingInteraction.booking, {
        equipmentItemId: currentBookingInteraction.equipmentItemId,
        startDate: currentBookingInteraction.startDate,
        endDate: currentBookingInteraction.endDate
      });
    };

    window.addEventListener("pointermove", handlePointerMove);
    window.addEventListener("pointerup", handlePointerUp);
    window.addEventListener("pointercancel", handlePointerUp);

    return () => {
      window.removeEventListener("pointermove", handlePointerMove);
      window.removeEventListener("pointerup", handlePointerUp);
      window.removeEventListener("pointercancel", handlePointerUp);
    };
  }, [firstDay, hasActivePointerInteraction, onBookingClick, onBookingQuickUpdate, onBookingScopeUpdate, onSelectionComplete]);

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

    const previousUserSelect = document.body.style.userSelect;
    document.body.style.userSelect = "none";

    return () => {
      document.body.style.userSelect = previousUserSelect;
    };
  }, [selectionDraft]);

  const getCompactWeekdayLabel = (day: string) => {
    const weekdayIndex = new Date(`${day}T12:00:00.000Z`).getUTCDay();
    return ["ND", "PN", "WT", "SR", "CZ", "PT", "SO"][weekdayIndex] ?? "??";
  };

  const maybeRequestFutureRange = () => {
    if (!onRequestFutureRange || interactionsLocked) {
      return;
    }

    const scroller = scrollerRef.current;
    const currentLastDay = daysRef.current[daysRef.current.length - 1];

    if (!scroller || !currentLastDay) {
      return;
    }

    const remainingRight = scroller.scrollWidth - scroller.clientWidth - scroller.scrollLeft;
    const threshold = Math.max(effectiveDayWidth * 5, 150);

    if (remainingRight > threshold) {
      return;
    }

    if (lastForwardRangeRequestRef.current === currentLastDay) {
      return;
    }

    lastForwardRangeRequestRef.current = currentLastDay;
    onRequestFutureRange();
  };

  const isSelected = (rowIndex: number, dayIndex: number) => {
    if (!selectionDraft) {
      return false;
    }

    const normalized = normalizeSelection(selectionDraft);

    return (
      rowIndex >= normalized.startRow &&
      rowIndex <= normalized.endRow &&
      dayIndex >= normalized.startDay &&
      dayIndex <= normalized.endDay
    );
  };

  const rowStates: RowRenderState[] = visibleItems.map((item, rowIndex) => {
    const verticalResizeRange =
      bookingInteraction?.kind === "resize-vertical"
        ? {
            start: Math.min(bookingInteraction.startRow, bookingInteraction.endRow),
            end: Math.max(bookingInteraction.startRow, bookingInteraction.endRow)
          }
        : null;
    const previewOnRow = bookingInteraction?.kind === "move" && bookingInteraction.equipmentItemId === item.id;
    const previewFromOtherRow =
      bookingInteraction?.kind === "move" &&
      bookingInteraction.booking.equipmentItemId !== item.id &&
      bookingInteraction.equipmentItemId === item.id
        ? bookingInteraction.booking
        : null;
    const rowBookings: BookingWithContext[] = (previewFromOtherRow ? [...item.bookings, previewFromOtherRow] : item.bookings).map(
      (booking) => ({
        ...booking,
        itemName: item.name,
        categoryName: item.categoryName
      })
    );
    const renderedBookings = rowBookings
      .map((booking) => {
        const bookingPreview = getBookingPreviewDraft(booking, bookingInteraction);

        return bookingPreview
          ? {
              ...booking,
              equipmentItemId: bookingPreview.equipmentItemId,
              startDate: bookingPreview.startDate,
              endDate: bookingPreview.endDate
            }
          : booking;
      })
      .filter((booking) => booking.equipmentItemId === item.id);
    const rowLayout = buildRowBookingLayout(renderedBookings);
    const hasStackedLanes = rowLayout.maxLane > 0;
    const bookingBarHeightForRow = hasStackedLanes ? stackedBookingBarHeight : singleBookingBarHeight;
    const bookingTopOffsetForRow = hasStackedLanes ? stackedBookingTopOffset : singleBookingTopOffset;
    const laneStep = hasStackedLanes ? 15 : 0;
    const rowMinHeight = Math.max(
      effectiveRowHeight,
      bookingBarHeightForRow + rowLayout.maxLane * laneStep + bookingTopOffsetForRow + Math.max(bookingTopOffsetForRow, 1)
    );

    return {
      item,
      rowIndex,
      previewOnRow: previewOnRow || Boolean(verticalResizeRange && rowIndex >= verticalResizeRange.start && rowIndex <= verticalResizeRange.end),
      renderedBookings,
      rowLayout,
      hasStackedLanes,
      bookingBarHeight: bookingBarHeightForRow,
      bookingTopOffset: bookingTopOffsetForRow,
      laneStep,
      rowMinHeight
    };
  });

  const rowStateByItemId = new Map(rowStates.map((rowState) => [rowState.item.id, rowState]));
  const { mergedBlockByBookingId, mergedBlocksByTopRowIndex } = buildMergedBookingBlocks({
    dayCount: days.length,
    effectiveDayWidth,
    firstDay,
    labelWidth,
    rowStates
  });

  return (
    <div className="overflow-hidden rounded-[30px] border border-line bg-white shadow-soft">
      <div
        ref={scrollerRef}
        className="overflow-auto overscroll-contain"
        onScroll={maybeRequestFutureRange}
        style={{
          maxHeight: scrollerMaxHeight,
          touchAction: mobileMode && selectionEnabled ? "none" : "pan-x pan-y"
        }}
      >
        <div className="min-w-max" style={{ width: labelWidth + days.length * effectiveDayWidth }}>
          <div
            className="sticky top-0 z-30 grid border-b border-line bg-[#f9f4eb]/95 backdrop-blur"
            style={{ gridTemplateColumns }}
          >
            <div
              className={cn(
                "sticky left-0 z-30 border-r border-line bg-[#f9f4eb]/95",
                mobileMode ? "px-4 py-3" : "px-2 py-1.5"
              )}
            >
              <p className={cn("uppercase tracking-[0.22em] text-muted", mobileMode ? "text-xs" : "text-[10px]")}>Urządzenia</p>
            </div>
            {days.map((day) => {
              const date = new Date(`${day}T12:00:00.000Z`);

              return (
                <div
                  key={day}
                  className={cn(
                    "border-r border-line text-center",
                    mobileMode ? "px-2 py-3" : "px-1 py-1.5",
                    day === today && "bg-today"
                  )}
                >
                  <p className={cn("uppercase tracking-[0.16em] text-muted", mobileMode ? "text-[11px]" : "text-[10px]")}>
                    {mobileMode ? new Intl.DateTimeFormat("pl-PL", { weekday: "short" }).format(date) : getCompactWeekdayLabel(day)}
                  </p>
                  <p className={cn("font-semibold text-ink", mobileMode ? "mt-1 text-sm" : "mt-0.5 text-[11px]")}>
                    {mobileMode
                      ? new Intl.DateTimeFormat("pl-PL", { day: "2-digit", month: "2-digit" }).format(date)
                      : new Intl.DateTimeFormat("pl-PL", { day: "2-digit", month: "2-digit" }).format(date)}
                  </p>
                </div>
              );
            })}
          </div>

          {groups.map((group) => {
            const isCollapsed = collapsedGroups.includes(group.categoryId);

            return (
              <div key={group.categoryId}>
                <div className="grid border-b border-line/70 bg-[#f2ece1]" style={{ gridTemplateColumns }}>
                  <button
                    className={cn(
                      "sticky left-0 z-20 flex border-r border-line bg-[#f2ece1] text-left",
                      mobileMode ? "items-center gap-3 px-4 py-3" : "items-center gap-2 px-2 py-1.5"
                    )}
                    onClick={() => onToggleGroup(group.categoryId)}
                  >
                    {isCollapsed ? <ChevronRight className="h-4 w-4 text-muted" /> : <ChevronDown className="h-4 w-4 text-muted" />}
                    <div>
                      <p className={cn("font-semibold text-ink", mobileMode ? "text-sm" : "text-xs leading-none")}>{group.categoryName}</p>
                      <p className={cn("text-muted", mobileMode ? "text-xs" : "mt-0.5 text-[10px] leading-none")}>{group.visibleItems} urządzeń</p>
                    </div>
                  </button>
                  <div
                    className={cn("flex items-center gap-2", mobileMode ? "px-4 py-3" : "px-2 py-1.5")}
                    style={{ gridColumn: `2 / span ${days.length}` }}
                  >
                    <Badge tone="neutral">{group.totalItems} w grupie</Badge>
                    {isCollapsed ? <Badge tone="accent">Zwinięte</Badge> : null}
                  </div>
                </div>

                {!isCollapsed
                  ? group.items.map((item) => {
                      const rowState = rowStateByItemId.get(item.id);

                      if (!rowState) {
                        return null;
                      }

                      const rowIndex = rowState.rowIndex;
                      const topMergedBlocks = mergedBlocksByTopRowIndex.get(rowIndex) ?? [];

                      return (
                        <div
                          key={item.id}
                          ref={(element) => setRowElement(item.id, element)}
                          className={cn("relative grid border-b border-line/60", rowState.previewOnRow && "bg-accent/5")}
                          style={{ gridTemplateColumns, minHeight: rowState.rowMinHeight }}
                        >
                          <div
                            className={cn(
                              "sticky left-0 z-20 border-r border-line bg-white",
                              mobileMode ? "flex items-center gap-3 px-4 py-3" : "px-2 py-1"
                            )}
                            title={`${item.name} • ${item.serialNumber || "Brak S/N"}${item.assetTag ? ` • ${item.assetTag}` : ""}`}
                          >
                            {mobileMode ? (
                              <div className="rounded-2xl bg-[#eff4ef] p-2 text-accent">
                                <LaptopMinimalCheck className="h-4 w-4" />
                              </div>
                            ) : null}
                            <div className="min-w-0">
                              <p className={cn("truncate font-semibold text-ink", mobileMode ? "text-base" : "text-[14px] leading-none")}>
                                {item.name}
                              </p>
                              {mobileMode ? (
                                <p className="truncate text-xs text-muted">
                                  {item.serialNumber || "Brak S/N"} {item.assetTag ? `• ${item.assetTag}` : ""}
                                </p>
                              ) : null}
                            </div>
                          </div>

                          {days.map((day, dayIndex) => {
                            const busy = rowState.renderedBookings.some((booking) => isDateInsideBooking(day, booking));
                            const conflictDay = rowState.rowLayout.conflictDays.has(day);

                            return (
                              <div
                                key={`${item.id}-${day}`}
                                className={cn(
                                  "border-r border-line/50 transition",
                                  conflictDay ? "bg-[#f5cfd0]" : busy ? "bg-busy/35" : "bg-free/65",
                                  day === today && !conflictDay && "bg-today",
                                  selectionEnabled && !interactionsLocked && "hover:bg-accent/10",
                                  isSelected(rowIndex, dayIndex) && "selection-outline selection-fill"
                                )}
                                onPointerDown={(event) => {
                                  if (event.button !== 0 || !selectionEnabled || interactionsLocked) {
                                    return;
                                  }

                                  event.preventDefault();
                                  event.currentTarget.setPointerCapture?.(event.pointerId);
                                  setBookingInteraction(null);
                                  setSelectionDraft({
                                    startRow: rowIndex,
                                    endRow: rowIndex,
                                    startDay: dayIndex,
                                    endDay: dayIndex
                                  });
                                }}
                                onPointerEnter={() => {
                                  if (!selectionDraftRef.current || interactionsLocked) {
                                    return;
                                  }

                                  updateSelectionTarget({ rowIndex, dayIndex });
                                }}
                                onPointerMove={(event) => {
                                  if (!selectionDraftRef.current || interactionsLocked) {
                                    return;
                                  }

                                  event.preventDefault();
                                  updateSelectionTarget({ rowIndex, dayIndex });
                                }}
                              />
                            );
                          })}

                          {topMergedBlocks.map((block) => (
                            <div
                              key={block.blockId}
                              className={cn(
                                "absolute z-10 flex items-center justify-center rounded-2xl bg-[#79d98b] font-semibold text-[#0f4320]",
                                mobileMode ? "px-3 text-sm" : "px-2 text-[11px] leading-none"
                              )}
                              role="button"
                              tabIndex={0}
                              style={{
                                height: block.height,
                                left: block.left,
                                top: block.top,
                                width: block.width
                              }}
                              onClick={() => onBookingClick(block.representative)}
                              onKeyDown={(event) => {
                                if (event.key === "Enter" || event.key === " ") {
                                  event.preventDefault();
                                  onBookingClick(block.representative);
                                }
                              }}
                              onPointerDown={(event) => {
                                if (interactionsLocked) {
                                  return;
                                }

                                const intent = resolveBarPointerIntent(event, {
                                  allowResizeEnd: false
                                });

                                if (intent.kind !== "resize-vertical") {
                                  return;
                                }

                                event.preventDefault();
                                event.stopPropagation();
                                setSelectionDraft(null);
                                setBookingInteraction({
                                  kind: "resize-vertical",
                                  booking: block.representative,
                                  startRow: block.topRowIndex,
                                  endRow: block.bottomRowIndex,
                                  initialStartRow: block.topRowIndex,
                                  initialEndRow: block.bottomRowIndex,
                                  direction: intent.direction
                                });
                              }}
                            >
                              <span className="relative -top-[2px] block max-w-full truncate px-2 text-center">
                                {block.representative.customerName}
                              </span>
                            </div>
                          ))}

                          {rowState.renderedBookings.map((booking) => {
                            const startIndex = Math.max(0, dayOffset(firstDay, booking.startDate));
                            const endIndex = Math.min(days.length - 1, dayOffset(firstDay, booking.endDate));

                            if (endIndex < 0 || startIndex > days.length - 1) {
                              return null;
                            }

                            const bookingPreview = bookingInteraction?.booking.id === booking.id ? bookingInteraction : null;
                            const laneIndex = rowState.rowLayout.laneByBookingId.get(booking.id) ?? 0;
                            const bookingHasConflict = rowState.rowLayout.conflictBookingIds.has(booking.id);
                            const resizeHandleVisible = Boolean(lastDay && booking.endDate <= lastDay);
                            const mergedBlock = mergedBlockByBookingId.get(booking.id);
                            const hideUnderlyingBar = Boolean(mergedBlock);

                            return (
                              <div
                                key={`${booking.id}-${item.id}`}
                                aria-label={`${booking.customerName} • ${booking.startDate} - ${booking.endDate}`}
                                className={cn(
                                  "group absolute flex items-center rounded-2xl bg-[#79d98b] text-left font-semibold text-[#0f4320]",
                                  mobileMode ? "px-3 text-sm" : "px-2 text-[11px] leading-none",
                                  bookingHasConflict && "bg-[#efb7ab] text-[#6f251d] ring-1 ring-[#cf7d7d]/80",
                                  interactionsLocked ? "cursor-default" : "cursor-grab active:cursor-grabbing",
                                  bookingPreview && "z-10 ring-2 ring-[#1d8f47]/25",
                                  hideUnderlyingBar && "opacity-0"
                                )}
                                role="button"
                                style={{
                                  height: rowState.bookingBarHeight,
                                  left: labelWidth + startIndex * effectiveDayWidth + 3,
                                  top: rowState.bookingTopOffset + laneIndex * rowState.laneStep,
                                  width: Math.max((endIndex - startIndex + 1) * effectiveDayWidth - 6, 18)
                                }}
                                tabIndex={0}
                                onKeyDown={(event) => {
                                  if (event.key === "Enter" || event.key === " ") {
                                    event.preventDefault();
                                    onBookingClick(booking);
                                  }
                                }}
                                onPointerDown={(event) => {
                                  if (interactionsLocked) {
                                    return;
                                  }

                                  const intent = resolveBarPointerIntent(event, {
                                    allowResizeEnd: resizeHandleVisible
                                  });
                                  const target = resolveGridTarget(event.clientX, event.clientY);

                                  event.preventDefault();
                                  event.stopPropagation();
                                  setSelectionDraft(null);

                                  if (intent.kind === "resize-vertical") {
                                    setBookingInteraction({
                                      kind: "resize-vertical",
                                      booking,
                                      startRow: rowIndex,
                                      endRow: rowIndex,
                                      initialStartRow: rowIndex,
                                      initialEndRow: rowIndex,
                                      direction: intent.direction
                                    });
                                    return;
                                  }

                                  if (intent.kind === "resize-end") {
                                    setBookingInteraction({
                                      kind: "resize-end",
                                      booking,
                                      equipmentItemId: booking.equipmentItemId,
                                      startDate: booking.startDate,
                                      endDate: booking.endDate,
                                      pointerStartDay: target?.dayIndex ?? endIndex
                                    });
                                    return;
                                  }

                                  setBookingInteraction({
                                    kind: "move",
                                    booking,
                                    equipmentItemId: booking.equipmentItemId,
                                    startDate: booking.startDate,
                                    endDate: booking.endDate,
                                    pointerStartDay: target?.dayIndex ?? startIndex
                                  });
                                }}
                              >
                                <span className="relative -top-[2px] truncate pr-3">{booking.customerName}</span>
                              </div>
                            );
                          })}
                        </div>
                      );
                    })
                  : null}
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
};
