import { useState, useRef, useCallback, useEffect } from 'react'
import type { ReactNode } from 'react'
import { addDays, format, startOfDay, differenceInDays, parseISO, isToday } from 'date-fns'
import { ru } from 'date-fns/locale'
import { ChevronLeft, ChevronRight, Plus, CalendarDays, ChevronDown, AlignJustify, Clock } from 'lucide-react'
import { cn, BOOKING_STATUS_COLORS, BOOKING_STATUS_LABELS, SOURCE_LABELS } from '../../lib/utils'
import type { Room, Booking, DraftBooking } from '../../types'
import type { RentalObject, RentalBooking } from '../../data/rentalData'
import { BookingModal } from '../bookings/BookingModal'
import { BookingDetailPanel } from '../bookings/BookingDetailPanel'
import { RentalBookingModal } from '../rental/RentalBookingModal'

const CELL_WIDTH = 52
const ROW_HEIGHT = 56
const ROW_HEIGHT_COMPACT = 34
const LABEL_WIDTH = 160
const DAYS_VISIBLE = 30

export type BookingLock = { checkIn: string; checkOut: string; lockedBy: string }

interface BookingCalendarProps {
  rooms: Room[]
  bookings: Booking[]
  slug?: string
  onBookingCreate: (b: Partial<Booking>) => void
  onBookingUpdate: (id: string, b: Partial<Booking>) => void
  onBookingBulkUpdate?: (updates: Array<{ id: string; data: Partial<Booking> }>) => void
  fadingBookingIds?: Set<string>
  rentalObjects?: RentalObject[]
  rentalBookings?: RentalBooking[]
  onRentalBookingCreate?: (b: RentalBooking) => void
  locks?: Map<string, BookingLock>
  onDraftStart?: (roomId: string, checkIn: string, checkOut: string) => void
  onDraftCancel?: (roomId: string) => void
  wsConnected?: boolean
}

const CATEGORY_ORDER: Record<string, number> = {
  'Стандарт':    0,
  'Делюкс':      1,
  'Полулюкс':    2,
  'Люкс':        3,
  'Пентхаус':    4,
  'Апартаменты': 5,
}

function getRoomTypeColor(type: string): string {
  const map: Record<string, string> = {
    'Стандарт':     'bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300',
    'Делюкс':       'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
    'Полулюкс':     'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300',
    'Люкс':         'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300',
    'Пентхаус':     'bg-rose-100 dark:bg-rose-900/30 text-rose-700 dark:text-rose-300',
    'Апартаменты':  'bg-teal-100 dark:bg-teal-900/30 text-teal-700 dark:text-teal-300',
  }
  return map[type] ?? 'bg-slate-100 text-slate-600 dark:bg-slate-700 dark:text-slate-300'
}

export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBookingUpdate, onBookingBulkUpdate, fadingBookingIds, rentalObjects, rentalBookings, onRentalBookingCreate, locks = new Map(), onDraftStart, onDraftCancel, wsConnected }: BookingCalendarProps) {
  const [startDate, setStartDate] = useState(() => startOfDay(new Date()))
  const [visibleDays, setVisibleDays] = useState(DAYS_VISIBLE)

  // Date picker state
  const [showNavPicker, setShowNavPicker] = useState(false)
  const [pickerDateInput, setPickerDateInput] = useState(format(new Date(), 'yyyy-MM-dd'))
  const navPickerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (!showNavPicker) return
    const handler = (e: MouseEvent) => {
      if (navPickerRef.current && !navPickerRef.current.contains(e.target as Node)) {
        setShowNavPicker(false)
      }
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [showNavPicker])

  // Drag-to-book state
  const [draft, setDraft] = useState<DraftBooking | null>(null)
  const [dragStart, setDragStart] = useState<{ roomId: string; dayIdx: number } | null>(null)
  const [dragEnd, setDragEnd] = useState<number | null>(null)

  // Drag-to-move booking state
  const [movingBooking, setMovingBooking] = useState<Booking | null>(null)
  const [moveTargetRoomId, setMoveTargetRoomId] = useState<string | null>(null)
  const [ghostPos, setGhostPos] = useState<{ x: number; y: number } | null>(null)
  const movingBookingRef = useRef<Booking | null>(null)
  const moveTargetRoomIdRef = useRef<string | null>(null)  // всегда актуален, без stale closure
  const bookingsRef = useRef<Booking[]>(bookings)
  const didDragRef = useRef(false)
  movingBookingRef.current = movingBooking
  bookingsRef.current = bookings

  // Compact mode (default from Settings → Appearance)
  const [compact, setCompact] = useState(
    () => localStorage.getItem('calendarCompact') === 'true',
  )
  const rowHeight = compact ? ROW_HEIGHT_COMPACT : ROW_HEIGHT

  // Mobile detection
  const [isMobile, setIsMobile] = useState(() => window.innerWidth < 640)
  useEffect(() => {
    const h = () => setIsMobile(window.innerWidth < 640)
    window.addEventListener('resize', h)
    return () => window.removeEventListener('resize', h)
  }, [])
  const labelWidth = isMobile ? 80 : LABEL_WIDTH

  // Modals
  const [bookingModalDraft, setBookingModalDraft] = useState<DraftBooking | null>(null)
  const [selectedBooking, setSelectedBooking] = useState<Booking | null>(null)
  const [rentalModal, setRentalModal] = useState<{ obj: RentalObject; date: string } | null>(null)

  const gridRef = useRef<HTMLDivElement>(null)

  const dates = Array.from({ length: visibleDays }, (_, i) => addDays(startDate, i))

  // Sorted+grouped rooms
  const sortedRooms = [...rooms].sort((a, b) => {
    const ao = CATEGORY_ORDER[a.type] ?? 99
    const bo = CATEGORY_ORDER[b.type] ?? 99
    if (ao !== bo) return ao - bo
    return a.number.localeCompare(b.number, 'ru', { numeric: true })
  })

  const shiftDays = (n: number) => setStartDate(d => addDays(d, n))

  const getBlockStyle = (booking: Booking) => {
    const start = parseISO(booking.checkIn)
    const end   = parseISO(booking.checkOut)
    const rawColStart = differenceInDays(start, startDate)
    const rawColEnd   = differenceInDays(end, startDate)
    if (rawColStart >= visibleDays || rawColEnd <= 0) return null

    const INSET = Math.round(CELL_WIDTH / 3)
    const isClippedLeft  = rawColStart <= 0
    const isClippedRight = rawColEnd > visibleDays

    const colStart = Math.max(0, rawColStart)
    const colEnd   = Math.min(visibleDays, rawColEnd)

    const leftPx  = colStart * CELL_WIDTH + (isClippedLeft  ? 0 : INSET)
    const rightPx = colEnd   * CELL_WIDTH + (isClippedRight ? 0 : INSET)

    return {
      left:  leftPx + 2,
      width: Math.max(8, rightPx - leftPx - 4),
    }
  }

  const handleCellMouseDown = useCallback((roomId: string, dayIdx: number, e: React.MouseEvent) => {
    if (e.button !== 0) return
    if (movingBookingRef.current) return
    e.preventDefault()
    setDragStart({ roomId, dayIdx })
    setDragEnd(dayIdx)
  }, [])

  const handleCellMouseEnter = useCallback((dayIdx: number) => {
    if (!dragStart) return
    setDragEnd(dayIdx)
  }, [dragStart])

  const handleMouseUp = useCallback(() => {
    if (!dragStart || dragEnd === null) return
    const minDay = Math.min(dragStart.dayIdx, dragEnd)
    const maxDay = Math.max(dragStart.dayIdx, dragEnd)
    const checkIn = format(addDays(startDate, minDay), 'yyyy-MM-dd')
    const checkOut = format(addDays(startDate, maxDay + 1), 'yyyy-MM-dd')
    setBookingModalDraft({ roomId: dragStart.roomId, checkIn, checkOut })
    onDraftStart?.(dragStart.roomId, checkIn, checkOut)
    setDragStart(null)
    setDragEnd(null)
    setDraft(null)
  }, [dragStart, dragEnd, startDate, onDraftStart, onBookingUpdate])

  const getLockStyle = (roomId: string) => {
    const lock = locks.get(roomId)
    if (!lock) return null
    return getBlockStyle({ checkIn: lock.checkIn, checkOut: lock.checkOut, roomId } as Booking)
  }

  const getDraftStyle = (roomId: string) => {
    if (!dragStart || dragEnd === null || dragStart.roomId !== roomId) return null
    const minDay = Math.min(dragStart.dayIdx, dragEnd)
    const maxDay = Math.max(dragStart.dayIdx, dragEnd)
    return {
      left: minDay * CELL_WIDTH,
      width: (maxDay - minDay + 1) * CELL_WIDTH - 2,
    }
  }

  return (
    <div className="flex flex-col h-full" onMouseUp={handleMouseUp} onMouseLeave={handleMouseUp}>
      {/* Toolbar */}
      <div className="flex items-center gap-3 px-4 py-3 border-b border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 shrink-0 flex-wrap gap-y-2">
        <div className="flex items-center gap-1.5">
          <button onClick={() => shiftDays(-7)} className="btn-ghost p-2"><ChevronLeft size={16} /></button>

          {/* Date / period picker */}
          <div className="relative" ref={navPickerRef}>
            <button
              onClick={() => setShowNavPicker(v => !v)}
              className={cn(
                'btn-secondary flex items-center gap-1.5 px-2.5 py-1.5 text-xs',
                showNavPicker && 'bg-slate-200 dark:bg-slate-600',
              )}
            >
              <CalendarDays size={12} className={isToday(startDate) ? 'text-brand-600' : 'text-slate-400'} />
              <span className={cn('font-medium', isToday(startDate) ? 'text-brand-600' : '')}>
                {isToday(startDate) ? 'Сегодня' : format(startDate, 'd MMM', { locale: ru })}
              </span>
              <span className="text-slate-400">·</span>
              <span className="text-slate-400">{visibleDays}д</span>
              <ChevronDown size={11} className="text-slate-400" />
            </button>

            {showNavPicker && (
              <div className="absolute top-full left-0 mt-1 z-50 bg-white dark:bg-slate-800 rounded-xl border border-slate-200 dark:border-slate-700 shadow-xl p-4 w-64">
                <p className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2">Начало периода</p>
                <div className="flex gap-2 mb-3">
                  <input
                    type="date"
                    value={pickerDateInput}
                    onChange={e => setPickerDateInput(e.target.value)}
                    className="input text-sm py-1.5 flex-1"
                  />
                  <button
                    onClick={() => {
                      const today = format(new Date(), 'yyyy-MM-dd')
                      setPickerDateInput(today)
                      setStartDate(startOfDay(new Date()))
                    }}
                    className="btn-secondary text-xs px-2.5 shrink-0"
                  >
                    Сег.
                  </button>
                </div>

                <p className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2">Дней в окне</p>
                <div className="flex gap-1.5 flex-wrap mb-4">
                  {[14, 21, 30, 45, 60].map(d => (
                    <button
                      key={d}
                      onClick={() => setVisibleDays(d)}
                      className={cn(
                        'px-2.5 py-1 rounded-lg text-xs font-medium border transition-colors',
                        visibleDays === d
                          ? 'bg-brand-600 border-brand-600 text-white'
                          : 'bg-white dark:bg-slate-700 border-slate-200 dark:border-slate-600 text-slate-600 dark:text-slate-300 hover:border-brand-400',
                      )}
                    >
                      {d}д
                    </button>
                  ))}
                </div>

                <button
                  onClick={() => {
                    const parsed = new Date(pickerDateInput)
                    if (!isNaN(parsed.getTime())) setStartDate(startOfDay(parsed))
                    setShowNavPicker(false)
                  }}
                  className="btn-primary w-full justify-center text-sm py-1.5"
                >
                  Показать
                </button>
              </div>
            )}
          </div>

          <button onClick={() => shiftDays(7)} className="btn-ghost p-2"><ChevronRight size={16} /></button>
        </div>

        <div className="flex items-center gap-2">
          <span className="text-sm font-medium text-slate-700 dark:text-slate-300 capitalize">
            {format(startDate, 'LLLL yyyy', { locale: ru })}
          </span>
          {/* Mobile-only + button next to month name */}
          <button
            className="sm:hidden btn-primary p-1.5"
            onClick={() => {
              const today = format(new Date(), 'yyyy-MM-dd')
              const tomorrow = format(addDays(new Date(), 1), 'yyyy-MM-dd')
              setBookingModalDraft({ roomId: rooms[0]?.id ?? '', checkIn: today, checkOut: tomorrow })
            }}
          >
            <Plus size={15} />
          </button>
        </div>

        <div className="flex-1" />

        {/* Legend */}
        <div className="hidden lg:flex items-center gap-3 text-xs text-slate-500">
          {(['confirmed', 'checked_in', 'checked_out', 'inquiry'] as const).map(s => (
            <div key={s} className="flex items-center gap-1.5">
              <div className={cn('w-3 h-3 rounded-sm', BOOKING_STATUS_COLORS[s].split(' ')[0])} />
              <span>{BOOKING_STATUS_LABELS[s]}</span>
            </div>
          ))}
        </div>

        {/* WebSocket status indicator */}
        {wsConnected !== undefined && (
          <div
            className="flex items-center gap-1.5 px-2 py-1 rounded-lg text-xs text-slate-400 dark:text-slate-500"
            title={wsConnected ? 'Синхронизация активна' : 'Нет соединения — переподключение...'}
          >
            <span className={cn(
              'w-1.5 h-1.5 rounded-full',
              wsConnected ? 'bg-emerald-500' : 'bg-slate-300 dark:bg-slate-600 animate-pulse',
            )} />
            <span className="hidden sm:inline">{wsConnected ? 'Онлайн' : 'Офлайн'}</span>
          </div>
        )}

        <button
          onClick={() => setCompact(v => { const next = !v; localStorage.setItem('calendarCompact', String(next)); return next })}
          title={compact ? 'Обычный вид' : 'Компактный вид'}
          className={cn(
            'hidden sm:flex btn-ghost items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium',
            compact && 'bg-brand-50 dark:bg-brand-900/20 text-brand-600 dark:text-brand-400',
          )}
        >
          <AlignJustify size={14} />
          Вид
        </button>

        <button
          onClick={() => {
            const today = format(new Date(), 'yyyy-MM-dd')
            const tomorrow = format(addDays(new Date(), 1), 'yyyy-MM-dd')
            setBookingModalDraft({ roomId: rooms[0]?.id ?? '', checkIn: today, checkOut: tomorrow })
          }}
          className="hidden sm:inline-flex btn-primary"
        >
          <Plus size={15} />
          <span className="hidden sm:inline">Новое бронирование</span>
        </button>
      </div>

      {/* Grid */}
      <div className="flex-1 overflow-auto" ref={gridRef}>
        <div style={{ minWidth: labelWidth + visibleDays * CELL_WIDTH }}>

          {/* Date header row */}
          <div
            className="flex sticky top-0 z-20 bg-white dark:bg-slate-800 border-b border-slate-200 dark:border-slate-700 shadow-sm"
            style={{ height: 48 }}
          >
            <div
              className="shrink-0 sticky left-0 z-30 bg-white dark:bg-slate-800 border-r border-slate-200 dark:border-slate-700 flex items-center px-3"
              style={{ width: labelWidth }}
            >
              <span className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Номер</span>
            </div>
            {dates.map((date, i) => {
              const isWe = date.getDay() === 0 || date.getDay() === 6
              const isTod = isToday(date)
              return (
                <div
                  key={i}
                  className={cn(
                    'shrink-0 flex flex-col items-center justify-center border-r border-slate-200 dark:border-slate-700 select-none',
                    isWe && 'bg-slate-50 dark:bg-slate-800/60',
                    isTod && 'bg-brand-50 dark:bg-brand-900/20',
                  )}
                  style={{ width: CELL_WIDTH }}
                >
                  <span className={cn(
                    'text-xs font-medium',
                    isTod ? 'text-brand-600 dark:text-brand-400' : isWe ? 'text-slate-400' : 'text-slate-500 dark:text-slate-400',
                  )}>
                    {format(date, 'EEEEEE', { locale: ru })}
                  </span>
                  <span className={cn(
                    'text-sm font-bold',
                    isTod ? 'text-brand-600 dark:text-brand-400' : 'text-slate-700 dark:text-slate-200',
                  )}>
                    {format(date, 'd')}
                  </span>
                </div>
              )
            })}
          </div>

          {/* Room rows grouped by category */}
          {(() => {
            const rows: ReactNode[] = []
            let lastCategory = ''
            sortedRooms.forEach(room => {
              // Category header
              if (room.type !== lastCategory) {
                lastCategory = room.type
                rows.push(
                  <div
                    key={`cat-${room.type}`}
                    className="flex sticky left-0 bg-slate-50 dark:bg-slate-700/40 border-b border-t border-slate-200 dark:border-slate-600"
                    style={{ height: 28 }}
                  >
                    <div
                      className="shrink-0 sticky left-0 z-10 bg-slate-50 dark:bg-slate-700/40 border-r border-slate-200 dark:border-slate-600 flex items-center px-2 overflow-hidden"
                      style={{ width: labelWidth }}
                    >
                      <span className={cn('text-xs font-semibold uppercase tracking-wide truncate', getRoomTypeColor(room.type).split(' ').filter(c => c.startsWith('text-')).join(' '))}>
                        {room.type}
                      </span>
                    </div>
                    {dates.map((_, i) => (
                      <div key={i} className="shrink-0 border-r border-slate-200 dark:border-slate-600" style={{ width: CELL_WIDTH }} />
                    ))}
                  </div>
                )
              }
              // Room row
              const roomBookings = bookings.filter(b => b.roomId === room.id && b.status !== 'cancelled')
              const draftStyle = getDraftStyle(room.id)
              rows.push(
                <div
                  key={room.id}
                  data-room-id={room.id}
                  className={cn(
                    'flex border-b border-slate-200 dark:border-slate-700 group hover:bg-slate-50/50 dark:hover:bg-slate-800/30',
                    movingBooking && moveTargetRoomId === room.id && 'bg-brand-50/60 dark:bg-brand-900/20',
                  )}
                  style={{ height: rowHeight }}
                >
                  {/* Room label */}
                  <div
                    className={cn('shrink-0 sticky left-0 z-10 bg-white dark:bg-slate-800 border-r border-slate-200 dark:border-slate-700 flex items-center gap-2 group-hover:bg-slate-50 dark:group-hover:bg-slate-800', isMobile ? 'px-2' : 'px-3')}
                    style={{ width: labelWidth }}
                  >
                    <div>
                      <div className="flex items-center gap-1.5">
                        <span className="text-sm font-bold text-slate-900 dark:text-slate-100">{room.number}</span>
                        {room.name && !isMobile && <span className="text-xs text-slate-500 dark:text-slate-400">{room.name}</span>}
                      </div>
                      {!compact && !isMobile && (
                        <span className={cn('text-xs px-1.5 py-0.5 rounded-md font-medium', getRoomTypeColor(room.type))}>
                          {room.type}
                        </span>
                      )}
                    </div>
                  </div>

                  {/* Day cells + booking blocks */}
                  <div className="relative flex-1">
                    <div className="flex h-full">
                      {dates.map((date, i) => {
                        const isWe = date.getDay() === 0 || date.getDay() === 6
                        const isTod = isToday(date)
                        return (
                          <div
                            key={i}
                            className={cn(
                              'shrink-0 h-full border-r border-slate-200 dark:border-slate-700 cursor-crosshair',
                              isWe && 'bg-slate-50 dark:bg-slate-800/60',
                              isTod && 'bg-brand-50/50 dark:bg-brand-900/10',
                            )}
                            style={{ width: CELL_WIDTH }}
                            onMouseDown={(e) => handleCellMouseDown(room.id, i, e)}
                            onMouseEnter={() => handleCellMouseEnter(i)}
                          />
                        )
                      })}
                    </div>

                    {/* Booking blocks */}
                    {roomBookings.map(booking => {
                      const style = getBlockStyle(booking)
                      if (!style) return null
                      const nights = differenceInDays(parseISO(booking.checkOut), parseISO(booking.checkIn))
                      const isFading = fadingBookingIds?.has(booking.id)
                      const isUnpaid = booking.paidAmount < booking.totalAmount
                      const guestCount = (booking.adults ?? 0) + (booking.children ?? 0)
                      const hourlyMatch = booking.notes?.match(/\[Почасово: (\d+):00–(\d+):00\]/)
                      return (
                        <div
                          key={booking.id}
                          className={cn(
                            'booking-block border-l-4 transition-all duration-700',
                            BOOKING_STATUS_COLORS[booking.status],
                            isFading && 'opacity-0 scale-y-0',
                            booking.status === 'checked_out' && 'opacity-50 pointer-events-none',
                            movingBooking?.id === booking.id && 'opacity-40 pointer-events-none',
                            booking.status !== 'checked_out' && !movingBooking && 'cursor-grab',
                          )}
                          style={{
                            left: style.left + 2,
                            width: style.width,
                            top: compact ? 2 : 4,
                            bottom: compact ? 2 : 4,
                            position: 'absolute',
                          }}
                          onMouseDown={(e) => {
                            if (e.button !== 0) return
                            e.stopPropagation()
                            e.preventDefault()
                            const startX = e.clientX
                            const startY = e.clientY
                            let dragging = false
                            const onMove = (ev: MouseEvent) => {
                              if (!dragging) {
                                if (Math.abs(ev.clientX - startX) > 5 || Math.abs(ev.clientY - startY) > 5) {
                                  dragging = true
                                  setMovingBooking(booking)
                                  moveTargetRoomIdRef.current = booking.roomId
                                  setMoveTargetRoomId(booking.roomId)
                                  document.body.style.cursor = 'grabbing'
                                }
                                return
                              }
                              setGhostPos({ x: ev.clientX, y: ev.clientY })
                              // Находим строку под курсором и запоминаем в ref (без stale closure)
                              const el = document.elementFromPoint(ev.clientX, ev.clientY)
                              const row = el?.closest('[data-room-id]') as HTMLElement | null
                              if (row?.dataset.roomId) {
                                moveTargetRoomIdRef.current = row.dataset.roomId
                                setMoveTargetRoomId(row.dataset.roomId)
                              }
                            }
                            const onUp = () => {
                              window.removeEventListener('mousemove', onMove)
                              window.removeEventListener('mouseup', onUp)
                              document.body.style.cursor = ''
                              if (dragging) {
                                // Читаем из ref — всегда актуальное значение, не stale closure
                                const targetRoomId = moveTargetRoomIdRef.current
                                if (targetRoomId && targetRoomId !== booking.roomId) {
                                  // Проверяем конфликт в целевом номере
                                  const hasConflict = bookingsRef.current.some(b =>
                                    b.roomId === targetRoomId &&
                                    b.id !== booking.id &&
                                    b.status !== 'cancelled' && b.status !== 'no_show' && b.status !== 'checked_out' &&
                                    b.checkIn < booking.checkOut && b.checkOut > booking.checkIn,
                                  )
                                  if (!hasConflict) {
                                    didDragRef.current = true
                                    onBookingUpdate(booking.id, { roomId: targetRoomId })
                                  }
                                }
                                setMovingBooking(null)
                                setMoveTargetRoomId(null)
                                setGhostPos(null)
                                moveTargetRoomIdRef.current = null
                              }
                            }
                            window.addEventListener('mousemove', onMove)
                            window.addEventListener('mouseup', onUp)
                          }}
                          onClick={(e) => {
                            e.stopPropagation()
                            if (didDragRef.current) { didDragRef.current = false; return }
                            setSelectedBooking(booking)
                          }}
                          title={`${booking.guestName} • ${booking.checkIn}${hourlyMatch ? ` ${hourlyMatch[1]}:00–${hourlyMatch[2]}:00` : ` – ${booking.checkOut}`}${isUnpaid ? ' • Не оплачено' : ''}`}
                        >
                          {isUnpaid && (
                            <span className="shrink-0 w-1.5 h-1.5 rounded-full bg-red-500 shadow-sm mr-1 mt-0.5" />
                          )}
                          {hourlyMatch && <Clock size={9} className="shrink-0 mr-0.5 opacity-80" />}
                          <span className="truncate text-xs font-semibold opacity-95 drop-shadow-sm">
                            {booking.guestName}
                          </span>
                          {!compact && hourlyMatch && style.width > 80 && (
                            <span className="ml-1 opacity-80 text-[10px] shrink-0">
                              {hourlyMatch[1]}–{hourlyMatch[2]}ч
                            </span>
                          )}
                          {!compact && !hourlyMatch && style.width > 90 && guestCount > 0 && (
                            <span className="ml-1.5 opacity-75 text-[10px] shrink-0">
                              {guestCount}г
                            </span>
                          )}
                          {!compact && !hourlyMatch && style.width > 130 && (
                            <span className="ml-1.5 opacity-75 text-[10px] shrink-0">
                              {nights}н
                            </span>
                          )}
                        </div>
                      )
                    })}

                    {/* Draft overlay */}
                    {draftStyle && (
                      <div
                        className="absolute top-2 bottom-2 bg-brand-400/40 border-2 border-brand-500 border-dashed rounded-md pointer-events-none"
                        style={{ left: draftStyle.left + 2, width: draftStyle.width }}
                      />
                    )}

                    {/* Lock overlay — another manager is editing this room */}
                    {(() => {
                      const lockStyle = getLockStyle(room.id)
                      if (!lockStyle) return null
                      const lock = locks.get(room.id)!
                      return (
                        <div
                          className="absolute top-1 bottom-1 rounded-md pointer-events-none z-10"
                          style={{
                            left: lockStyle.left + 2,
                            width: lockStyle.width,
                            background: 'repeating-linear-gradient(45deg, rgba(100,116,139,0.2) 0px, rgba(100,116,139,0.2) 4px, rgba(100,116,139,0.05) 4px, rgba(100,116,139,0.05) 10px)',
                            border: '1.5px dashed rgba(100,116,139,0.55)',
                          }}
                        >
                          {lockStyle.width > 60 && (
                            <span className="absolute inset-x-1 top-1/2 -translate-y-1/2 text-[9px] text-slate-500 dark:text-slate-400 font-medium truncate text-center leading-tight select-none">
                              ✏️ {lock.lockedBy}
                            </span>
                          )}
                        </div>
                      )
                    })()}
                  </div>
                </div>
              )
            })
            return rows
          })()}

          {/* ── Rental section ── */}
          {rentalObjects && rentalObjects.length > 0 && (
            <>
              {/* Separator */}
              <div className="flex sticky left-0 bg-slate-100 dark:bg-slate-700/60 border-b border-t border-slate-200 dark:border-slate-600"
                   style={{ height: 32 }}>
                <div
                  className="shrink-0 sticky left-0 z-10 bg-slate-100 dark:bg-slate-700/60 border-r border-slate-200 dark:border-slate-600 flex items-center px-4"
                  style={{ width: labelWidth }}
                >
                  <span className="text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wide">
                    Аренда объектов
                  </span>
                </div>
                {dates.map((_, i) => (
                  <div key={i} className="shrink-0 border-r border-slate-200 dark:border-slate-600"
                       style={{ width: CELL_WIDTH }} />
                ))}
              </div>

              {/* Rental object rows */}
              {rentalObjects.map(obj => {
                const totalSpan = obj.closeHour - obj.openHour
                const rentalRowH = Math.max(rowHeight, ROW_HEIGHT)
                return (
                  <div key={obj.id}
                       className="flex border-b border-slate-200 dark:border-slate-700"
                       style={{ height: rentalRowH }}>
                    {/* Label */}
                    <div
                      className="shrink-0 sticky left-0 z-10 bg-white dark:bg-slate-800 border-r border-slate-200 dark:border-slate-700 flex items-center gap-2 px-3"
                      style={{ width: labelWidth }}
                    >
                      <span className="text-base leading-none shrink-0">{obj.icon}</span>
                      <div className="min-w-0">
                        <p className="text-sm font-medium text-slate-800 dark:text-slate-200 truncate leading-tight">{obj.name}</p>
                        <p className="text-[10px] text-slate-400 whitespace-nowrap leading-tight mt-0.5">
                          {obj.pricePerHour.toLocaleString('ru-RU')} ₽/ч · {obj.pricePerDay.toLocaleString('ru-RU')} ₽/д
                        </p>
                      </div>
                    </div>

                    {/* Day cells */}
                    {dates.map((date, i) => {
                      const dateStr = format(date, 'yyyy-MM-dd')
                      const isWe = date.getDay() === 0 || date.getDay() === 6
                      const isTod = isToday(date)
                      const dayBookings = (rentalBookings ?? []).filter(
                        b => b.objectId === obj.id && b.date === dateStr && b.status !== 'cancelled',
                      )
                      const hasFullDay = dayBookings.some(b => b.isFullDay)

                      return (
                        <div
                          key={i}
                          onClick={() => setRentalModal({ obj, date: dateStr })}
                          className={cn(
                            'shrink-0 border-r border-slate-200 dark:border-slate-700 cursor-pointer relative',
                            'hover:bg-slate-50 dark:hover:bg-slate-700/40 transition-colors',
                            isWe && 'bg-amber-50/30 dark:bg-amber-900/10',
                            isTod && 'bg-brand-50/40 dark:bg-brand-900/10',
                          )}
                          style={{ width: CELL_WIDTH, height: rentalRowH }}
                        >
                          {hasFullDay ? (
                            /* Full day booking */
                            <div className={cn(
                              'absolute inset-1.5 rounded flex items-center justify-center text-white text-[10px] font-semibold',
                              obj.color,
                            )}>
                              Весь день
                            </div>
                          ) : dayBookings.length > 0 ? (
                            /* Hourly bookings — squares + times */
                            <div className="absolute inset-x-1 top-1.5 flex flex-col gap-0.5">
                              {/* One colored square per booking */}
                              <div className="flex gap-0.5 flex-wrap">
                                {dayBookings.map(b => (
                                  <div
                                    key={b.id}
                                    className={cn('w-3 h-3 rounded-[3px]', obj.color)}
                                    title={`${b.guestName} · ${b.startHour}:00–${b.endHour}:00`}
                                  />
                                ))}
                              </div>
                              {/* Working hours range */}
                              <span className="text-[9px] text-slate-400 dark:text-slate-500 leading-none">
                                {obj.openHour}:00–{obj.closeHour}:00
                              </span>
                              {/* Booked time slots */}
                              {dayBookings.map(b => (
                                <span key={b.id} className="text-[9px] text-slate-600 dark:text-slate-300 font-medium leading-none">
                                  {b.startHour}–{b.endHour}
                                </span>
                              ))}
                            </div>
                          ) : (
                            /* Empty — show "+" hint on hover */
                            <div className="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
                              <span className="text-xs text-slate-400">+</span>
                            </div>
                          )}
                        </div>
                      )
                    })}
                  </div>
                )
              })}
            </>
          )}
        </div>
      </div>

      {/* Booking create modal */}
      {bookingModalDraft && (
        <BookingModal
          open={true}
          draft={bookingModalDraft}
          rooms={rooms}
          bookings={bookings}
          onClose={() => {
            if (bookingModalDraft) onDraftCancel?.(bookingModalDraft.roomId)
            setBookingModalDraft(null)
          }}
          onSave={(data) => {
            onBookingCreate(data)
            setBookingModalDraft(null)
          }}
        />
      )}

      {/* Booking detail panel */}
      {selectedBooking && (
        <BookingDetailPanel
          booking={selectedBooking}
          room={rooms.find(r => r.id === selectedBooking.roomId)}
          rooms={rooms}
          allBookings={bookings}
          slug={slug}
          onClose={() => setSelectedBooking(null)}
          onUpdate={(id, data) => {
            onBookingUpdate(id, data)
            setSelectedBooking(null)
          }}
          onBulkUpdate={onBookingBulkUpdate ? (updates) => {
            onBookingBulkUpdate(updates)
            setSelectedBooking(null)
          } : undefined}
        />
      )}

      {/* Drag ghost element */}
      {movingBooking && ghostPos && (
        <div
          className={cn(
            'fixed z-[9999] pointer-events-none px-3 py-1.5 rounded-lg text-white text-xs font-semibold shadow-xl border-2 border-white/40',
            BOOKING_STATUS_COLORS[movingBooking.status],
          )}
          style={{ left: ghostPos.x + 14, top: ghostPos.y - 16 }}
        >
          {movingBooking.guestName}
        </div>
      )}

      {/* Rental booking modal */}
      {rentalModal && (
        <RentalBookingModal
          obj={rentalModal.obj}
          date={rentalModal.date}
          existingBookings={(rentalBookings ?? []).filter(
            b => b.objectId === rentalModal.obj.id && b.date === rentalModal.date,
          )}
          bookings={bookings}
          rooms={rooms}
          onClose={() => setRentalModal(null)}
          onSave={(b) => {
            onRentalBookingCreate?.(b)
            setRentalModal(null)
          }}
        />
      )}
    </div>
  )
}
