'use client'

import { memo, useMemo, useCallback } from'react'
import type { Consultant, AppointmentType, PlanningProject, Assignment } from'@/lib/planning-types'
import { formatDateKey, getISOWeek, isToday } from'@/lib/planning-config'
import type { CalendarColors } from'@/lib/planning-settings'
import type { CapacityCell } from'@/lib/planning-capacity'
import { computeTiles, getCellBg, hexToRgba } from'@/lib/planning/compute-tiles'
import type { DragSelectState } from'./hooks/use-grid-interaction'
import AssignmentTile from'./assignment-tile'

export type { TileInfo } from'@/lib/planning/compute-tiles'

// ── Constants ────────────────────────────────────────────────────────────────

const DAY_COL_W = 40
const ROW_H = 38

// ── Props ────────────────────────────────────────────────────────────────────

export interface PlanningRowProps {
 consultant: Consultant
 rowIndex: number
 days: Date[]
 assignmentMap: Map<string, Assignment[]>
 typeMap: Map<string, AppointmentType>
 projectMap: Map<string, PlanningProject>
 capacityMap: Map<string, CapacityCell>
 conflictCells: Set<string>
 holidayMap: Map<string, string>
 calendarColors: CalendarColors
 selectedWeeks: Set<number>
 selectionMode: boolean
 selectedIds: Set<string>
 syncStatusMap: Record<string, string>
 isHighlighted: boolean
 isCurrentUser: boolean
 dragSelect: DragSelectState | null
 onTileMove: (assignments: Assignment[], newStartDate: string, newConsultantId: string) => void
 onCardClick: (assignment: Assignment) => void
 onCardRightClick: (assignment: Assignment, x: number, y: number) => void
 onCtrlClickCard: (id: string) => void
 onToggleSelect: (id: string) => void
 onBulkRightClick: (x: number, y: number) => void
 onToggleHighlight:(consultantId: string) => void
 onTooltipShow: (
 assignment: Assignment,
 e: React.MouseEvent<HTMLDivElement>,
 startDate?: string,
 endDate?: string,
 ) => void
 onTooltipHide: () => void
 onCellMouseDown: (consultantId: string, dk: string, isSelect: boolean) => void
}

// ── Component ─────────────────────────────────────────────────────────────────

function PlanningRowInner({
 consultant, rowIndex, days,
 assignmentMap, typeMap, projectMap,
 capacityMap, conflictCells, holidayMap,
 calendarColors, selectedWeeks, selectionMode,
 selectedIds, syncStatusMap,
 isHighlighted, isCurrentUser,
 dragSelect,
 onTileMove,
 onCardClick, onCardRightClick, onCtrlClickCard,
 onToggleSelect, onBulkRightClick,
 onToggleHighlight, onTooltipShow, onTooltipHide,
 onCellMouseDown,
}: PlanningRowProps) {
 const selColor = calendarColors.selectionHighlightColor ??'#3B82F6'
 const selOp = calendarColors.selectionHighlightOpacity ?? 8
 const rowBg = isHighlighted ?'': rowIndex % 2 === 0 ?'bg-card':'bg-background'
 const rowBgStyle = isHighlighted
 ? { backgroundColor: hexToRgba(selColor, (selOp + 4) / 100) }
 : {}

 // Memoize tile computation — only recompute if this consultant's data changes
 const tiles = useMemo(
 () => computeTiles(consultant, days, assignmentMap, typeMap, projectMap),
 [consultant, days, assignmentMap, typeMap, projectMap],
 )

 // Context-menu handler varies by tile — create stable factory
 const makeContextMenuHandler = useCallback(
 (tileId: string) =>
 (a: Assignment, x: number, y: number) => {
 if (selectedIds.size > 1 && selectedIds.has(tileId)) {
 onBulkRightClick(x, y)
 } else if (!selectionMode) {
 onCardRightClick(a, x, y)
 }
 },
 [selectedIds, selectionMode, onBulkRightClick, onCardRightClick],
 )

 const handleTileClick = useCallback(
 (a: Assignment) => {
 if (selectionMode) { onToggleSelect(a.id); return }
 onCardClick(a)
 },
 [selectionMode, onToggleSelect, onCardClick],
 )

 return (
 <tr
 data-consultant-id={consultant.id}
 className={rowBg}
 style={rowBgStyle}
 >
 {/* Sticky name cell */}
 <td
 className={[
'sticky left-0 z-20 border-r border-b border-input px-2.5 py-1.5 whitespace-nowrap cursor-pointer select-none',
 rowBg,
 isHighlighted || isCurrentUser ?'border-l-[3px]':'',
 ].join(' ')}
 style={{
 ...rowBgStyle,
 ...(isHighlighted ? { borderLeftColor: selColor }
 : isCurrentUser ? { borderLeftColor:'#94A3B8'} : {}),
 }}
 onClick={() => onToggleHighlight(consultant.id)}
 title="Klicken zum Hervorheben"
 >
 <span className="font-medium text-foreground text-[12px]">{consultant.display_name}</span>
 {consultant.role ==='team_lead'&& (
 <span className="ml-1.5 text-[9px] font-bold uppercase tracking-wide bg-secondary text-primary-dark px-1 py-0.5 rounded">
 TL
 </span>
 )}
 </td>

 {/* Full-width overlay cell — day backgrounds + tiles */}
 <td
 colSpan={days.length}
 className="border-b border-input p-0 relative"
 style={{ height: ROW_H }}
 >
 {/* ── Day background cells ──────────────────────────────────── */}
 {days.map((day, di) => {
 const dk = formatDateKey(day)
 const cellKey = `${consultant.id}:${dk}`
 const todayDay = isToday(day)
 const holidayName = holidayMap.get(dk)
 const dow = day.getDay()
 const isWeekSel = selectedWeeks.has(getISOWeek(day)) && dow >= 1 && dow <= 5
 const hasConflict = conflictCells.has(cellKey)
 const cap = capacityMap.get(cellKey)
 const isOverbooked = cap?.overbooked ?? false

 const isInDragSelect = (() => {
 if (!dragSelect || dragSelect.consultantId !== consultant.id) return false
 const [s, e] = dragSelect.startDate <= dragSelect.endDate
 ? [dragSelect.startDate, dragSelect.endDate]
 : [dragSelect.endDate, dragSelect.startDate]
 return dk >= s && dk <= e
 })()

 const isMonthStart = day.getDate() === 1 && di > 0
 const bgColor = isInDragSelect
 ?'#BFDBFE'
 : getCellBg(day, dk, holidayMap, isHighlighted, isWeekSel, calendarColors)

 return (
 <div
 key={dk}
 className={[
'absolute top-0 bottom-0',
 hasConflict ?'relative':'',
 todayDay ?'border-l-[2px] border-l-[#3B82F6]':'',
 isInDragSelect ?'cursor-crosshair':'cursor-pointer',
 ].join(' ')}
 style={{
 left: di * DAY_COL_W,
 width: DAY_COL_W,
 backgroundColor: bgColor,
 borderLeft: isMonthStart ?'2px solid var(--input)': undefined,
 borderRight:'1px solid var(--input)',
 borderBottom: holidayName ?'1px dashed var(--input)': undefined,
 outline: hasConflict ?'2px solid #F59E0B'
 : isOverbooked ?'2px solid #DC2626':'none',
 outlineOffset:'-2px',
 }}
 onMouseDown={(e) => {
 if (e.button !== 0) return
 if ((e.target as HTMLElement).closest('[data-assignment-tile]')) return
 e.preventDefault()
 onCellMouseDown(consultant.id, dk, selectionMode)
 }}
 title={
 hasConflict
 ? `Mehrere Einträge am gleichen Tag — bitte prüfen`
 : isOverbooked
 ? `Überbuchung: ${cap!.bookedHours.toFixed(1)}h / ${cap!.capacityHours}h`
 : holidayName
 }
 >
 {/* ⚠️ conflict badge */}
 {hasConflict && (
 <span
 className="absolute top-0.5 right-0.5 z-10 text-[9px] leading-none select-none pointer-events-none"
 title="Mehrere Einträge am gleichen Tag — bitte prüfen"
 >
 ⚠️
 </span>
 )}
 </div>
 )
 })}

 {/* ── Assignment tiles ──────────────────────────────────────── */}
 {tiles.map((tile) => (
 <AssignmentTile
 key={tile.id}
 assignments={tile.assignments}
 color={tile.color}
 label={tile.label}
 dayWidth={DAY_COL_W}
 startColumnIndex={tile.startColumnIndex}
 spanDays={tile.spanDays}
 selectionMode={selectionMode}
 selected={selectedIds.has(tile.id)}
 syncStatus={syncStatusMap[tile.id]}
 onMove={onTileMove}
 onContextMenu={makeContextMenuHandler(tile.id)}
 onClick={handleTileClick}
 onCtrlClick={onCtrlClickCard}
 onToggleSelect={onToggleSelect}
 onTooltipShow={onTooltipShow}
 onTooltipHide={onTooltipHide}
 />
 ))}

 {/* ── Drag-select range highlight ───────────────────────────── */}
 {dragSelect?.consultantId === consultant.id && (() => {
 const [s, e] = dragSelect.startDate <= dragSelect.endDate
 ? [dragSelect.startDate, dragSelect.endDate]
 : [dragSelect.endDate, dragSelect.startDate]
 const si = days.findIndex((d) => formatDateKey(d) === s)
 const ei = days.findIndex((d) => formatDateKey(d) === e)
 if (si === -1) return null
 const endIdx = ei === -1 ? days.length - 1 : ei
 return (
 <div
 className="absolute top-0 bottom-0 pointer-events-none"
 style={{
 left: si * DAY_COL_W,
 width: (endIdx - si + 1) * DAY_COL_W,
 backgroundColor:'#BFDBFE',
 opacity: 0.6,
 zIndex: 5,
 }}
 />
 )
 })()}
 </td>
 </tr>
 )
}

// Custom equality: re-render only when this row's data actually changes.
// dragSelect changes frequently during mouse moves, but only one row at a time
// is affected (the one whose consultantId matches).
function rowPropsAreEqual(prev: PlanningRowProps, next: PlanningRowProps): boolean {
 if (prev.consultant !== next.consultant) return false
 if (prev.rowIndex !== next.rowIndex) return false
 if (prev.days !== next.days) return false
 if (prev.assignmentMap !== next.assignmentMap) return false
 if (prev.typeMap !== next.typeMap) return false
 if (prev.projectMap !== next.projectMap) return false
 if (prev.capacityMap !== next.capacityMap) return false
 if (prev.conflictCells !== next.conflictCells) return false
 if (prev.holidayMap !== next.holidayMap) return false
 if (prev.calendarColors !== next.calendarColors) return false
 if (prev.selectedWeeks !== next.selectedWeeks) return false
 if (prev.selectionMode !== next.selectionMode) return false
 if (prev.isHighlighted !== next.isHighlighted) return false
 if (prev.isCurrentUser !== next.isCurrentUser) return false
 if (prev.syncStatusMap !== next.syncStatusMap) return false
 if (prev.selectedIds !== next.selectedIds) return false

 // dragSelect: only matters if it involves this consultant
 const cid = next.consultant.id
 const prevDs = prev.dragSelect?.consultantId === cid ? prev.dragSelect : null
 const nextDs = next.dragSelect?.consultantId === cid ? next.dragSelect : null
 if (prevDs !== nextDs) {
 if (!prevDs && !nextDs) { /* equal */ }
 else if (!prevDs || !nextDs) return false
 else if (
 prevDs.startDate !== nextDs.startDate ||
 prevDs.endDate !== nextDs.endDate ||
 prevDs.isSelect !== nextDs.isSelect
 ) return false
 }

 // Callbacks should be stable (useCallback in parent)
 if (prev.onTileMove !== next.onTileMove) return false
 if (prev.onCardClick !== next.onCardClick) return false
 if (prev.onCardRightClick !== next.onCardRightClick) return false
 if (prev.onCtrlClickCard !== next.onCtrlClickCard) return false
 if (prev.onToggleSelect !== next.onToggleSelect) return false
 if (prev.onBulkRightClick !== next.onBulkRightClick) return false
 if (prev.onToggleHighlight!== next.onToggleHighlight)return false
 if (prev.onTooltipShow !== next.onTooltipShow) return false
 if (prev.onTooltipHide !== next.onTooltipHide) return false
 if (prev.onCellMouseDown !== next.onCellMouseDown) return false

 return true
}

export default memo(PlanningRowInner, rowPropsAreEqual)
