'use client'

/**
 * useGridInteraction — manages drag-select state for the planning grid.
 *
 * Responsibilities:
 *  - Track which cells are highlighted during a drag-select.
 *  - Attach/detach document-level mousemove + mouseup handlers.
 *  - Translate clientX → day index using the table's bounding rect.
 *
 * Tile drag/resize is intentionally NOT handled here — assignment-tile.tsx
 * manages its own imperative drag via document event listeners.
 */

import { useState, useRef, useEffect, useCallback, type RefObject } from 'react'
import { snapDayIndex } from '@/lib/planning/grid-snap'
import { formatDateKey } from '@/lib/planning-config'

export interface DragSelectState {
  consultantId: string
  startDate:    string
  endDate:      string
  isSelect:     boolean
}

interface Params {
  tableRef:       RefObject<HTMLTableElement | null>
  getDays:        () => Date[]
  onCellClick:    (consultantId: string, startDate: string, endDate: string) => void
  onSelectRange:  (consultantId: string, startDate: string, endDate: string) => void
}

interface Result {
  dragSelect:     DragSelectState | null
  startCellDrag:  (consultantId: string, date: string, isSelect: boolean) => void
}

export function useGridInteraction({
  tableRef,
  getDays,
  onCellClick,
  onSelectRange,
}: Params): Result {
  const [dragSelect, setDragSelect] = useState<DragSelectState | null>(null)

  // Refs so event handlers always see fresh values without re-registration
  const dragActive          = useRef(false)
  const pendingDragSelect   = useRef<DragSelectState | null>(null)
  const onCellClickRef      = useRef(onCellClick);     onCellClickRef.current     = onCellClick
  const onSelectRangeRef    = useRef(onSelectRange);   onSelectRangeRef.current   = onSelectRange
  const getDaysRef          = useRef(getDays);          getDaysRef.current          = getDays

  // Keep pendingDragSelect in sync with state (no extra re-render)
  pendingDragSelect.current = dragSelect

  useEffect(() => {
    function handleMouseUp() {
      if (!dragActive.current) return
      dragActive.current = false
      const sel = pendingDragSelect.current
      setDragSelect(null)
      if (!sel) return
      const [s, e] = sel.startDate <= sel.endDate
        ? [sel.startDate, sel.endDate]
        : [sel.endDate, sel.startDate]
      if (sel.isSelect) onSelectRangeRef.current(sel.consultantId, s, e)
      else              onCellClickRef.current(sel.consultantId, s, e)
    }

    function handleMouseMove(ev: MouseEvent) {
      if (!dragActive.current) return
      const tableEl = tableRef.current
      if (!tableEl) return
      const tableRect = tableEl.getBoundingClientRect()
      const days      = getDaysRef.current()
      const rawIdx    = snapDayIndex(ev.clientX, tableRect)
      const clamped   = Math.max(0, Math.min(rawIdx, days.length - 1))
      const d         = days[clamped]
      if (!d) return
      const newDk = formatDateKey(d)
      setDragSelect((prev) => {
        if (!prev || prev.endDate === newDk) return prev
        return { ...prev, endDate: newDk }
      })
    }

    document.addEventListener('mouseup',   handleMouseUp)
    document.addEventListener('mousemove', handleMouseMove)
    return () => {
      document.removeEventListener('mouseup',   handleMouseUp)
      document.removeEventListener('mousemove', handleMouseMove)
    }
  }, [tableRef])

  const startCellDrag = useCallback((consultantId: string, date: string, isSelect: boolean) => {
    dragActive.current = true
    setDragSelect({ consultantId, startDate: date, endDate: date, isSelect })
  }, [])

  return { dragSelect, startCellDrag }
}
