'use client'

import { useCallback, useEffect, useRef, useState } from 'react'
import type { GridEditorCell } from './types'
import { MIN_COL_WIDTH, MIN_ROW_HEIGHT, ROW_NUM_WIDTH } from './gridTableConstants'
import type { GridTableProps } from './gridTableConstants'
import { getCellColor, getRowHeight } from './gridTableUtils'
import { GridTableColumnHeader } from './GridTableColumnHeader'
import { GridTableRowHeader } from './GridTableRowHeader'
import { GridTableCell } from './GridTableCell'
import { GridTableColorMenu } from './GridTableColorMenu'

export function GridTable({
  zone,
  layoutMetrics,
  selectedCell,
  selectedCells,
  onSelectCell,
  onToggleCellSelection,
  onCellTextChange,
  onToggleColumnBold,
  onToggleRowHeader,
  onNavigate,
  onDeleteColumn,
  onAddColumn,
  onDeleteRow,
  onAddRow,
  onSetCellColor,
}: GridTableProps) {
  const containerRef = useRef<HTMLDivElement>(null)
  const [containerWidth, setContainerWidth] = useState(0)
  const [colorMenu, setColorMenu] = useState<{ cellId: string; x: number; y: number } | null>(null)

  // ----------------------------------------------------------------
  // Observe container width for scaling
  // ----------------------------------------------------------------
  useEffect(() => {
    const el = containerRef.current
    if (!el) return
    const ro = new ResizeObserver(([entry]) => {
      setContainerWidth(entry.contentRect.width)
    })
    ro.observe(el)
    return () => ro.disconnect()
  }, [])

  // ----------------------------------------------------------------
  // Compute column widths from OCR measurements
  // ----------------------------------------------------------------
  const [colWidthOverrides, setColWidthOverrides] = useState<number[] | null>(null)

  const columnWidthsPx = zone.columns.map((col) => col.x_max_px - col.x_min_px)
  const totalColWidthPx = columnWidthsPx.reduce((sum, w) => sum + w, 0)
  const zoneWidthPx = totalColWidthPx > 0
    ? totalColWidthPx
    : (zone.bbox_px.w || layoutMetrics?.page_width_px || 1)
  const scale = containerWidth > 0 ? (containerWidth - ROW_NUM_WIDTH) / zoneWidthPx : 1

  const effectiveColWidths = (colWidthOverrides ?? columnWidthsPx).map(
    (w) => Math.max(MIN_COL_WIDTH, w * scale),
  )

  // ----------------------------------------------------------------
  // Row height
  // ----------------------------------------------------------------
  const avgRowHeightPx = layoutMetrics?.avg_row_height_px ?? 30
  const [rowHeightOverrides, setRowHeightOverrides] = useState<Map<number, number>>(new Map())

  const computeRowHeight = (rowIndex: number, isHeader: boolean): number => {
    if (rowHeightOverrides.has(rowIndex)) {
      return rowHeightOverrides.get(rowIndex)!
    }
    return getRowHeight(zone, rowIndex, isHeader, avgRowHeightPx, scale)
  }

  // ----------------------------------------------------------------
  // Font size from layout metrics
  // ----------------------------------------------------------------
  const baseFontSize = layoutMetrics?.font_size_suggestion_px
    ? Math.max(11, layoutMetrics.font_size_suggestion_px * scale)
    : 13

  // ----------------------------------------------------------------
  // Keyboard navigation
  // ----------------------------------------------------------------
  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent, cellId: string) => {
      if (e.key === 'Tab') {
        e.preventDefault()
        onNavigate(cellId, e.shiftKey ? 'left' : 'right')
      } else if (e.key === 'Enter' && !e.shiftKey) {
        e.preventDefault()
        onNavigate(cellId, 'down')
      } else if (e.key === 'ArrowUp') {
        e.preventDefault()
        onNavigate(cellId, 'up')
      } else if (e.key === 'ArrowDown') {
        e.preventDefault()
        onNavigate(cellId, 'down')
      } else if (e.key === 'ArrowLeft' && e.altKey) {
        e.preventDefault()
        onNavigate(cellId, 'left')
      } else if (e.key === 'ArrowRight' && e.altKey) {
        e.preventDefault()
        onNavigate(cellId, 'right')
      } else if (e.key === 'Escape') {
        ;(e.target as HTMLElement).blur()
      }
    },
    [onNavigate],
  )

  // ----------------------------------------------------------------
  // Cell lookup
  // ----------------------------------------------------------------
  const cellMap = new Map<string, GridEditorCell>()
  for (const cell of zone.cells) {
    cellMap.set(`${cell.row_index}_${cell.col_index}`, cell)
  }

  // ----------------------------------------------------------------
  // Column resize (drag)
  // ----------------------------------------------------------------
  const handleColResizeStart = useCallback(
    (colIndex: number, startX: number) => {
      const baseWidths = colWidthOverrides ?? [...columnWidthsPx]

      const handleMouseMove = (e: MouseEvent) => {
        const deltaPx = (e.clientX - startX) / scale
        const newWidths = [...baseWidths]
        newWidths[colIndex] = Math.max(20, baseWidths[colIndex] + deltaPx)
        if (colIndex + 1 < newWidths.length) {
          newWidths[colIndex + 1] = Math.max(20, baseWidths[colIndex + 1] - deltaPx)
        }
        setColWidthOverrides(newWidths)
      }

      const handleMouseUp = () => {
        document.removeEventListener('mousemove', handleMouseMove)
        document.removeEventListener('mouseup', handleMouseUp)
        document.body.style.cursor = ''
        document.body.style.userSelect = ''
      }

      document.body.style.cursor = 'col-resize'
      document.body.style.userSelect = 'none'
      document.addEventListener('mousemove', handleMouseMove)
      document.addEventListener('mouseup', handleMouseUp)
    },
    [colWidthOverrides, columnWidthsPx, scale],
  )

  // ----------------------------------------------------------------
  // Row resize (drag)
  // ----------------------------------------------------------------
  const handleRowResizeStart = useCallback(
    (rowIndex: number, startY: number, currentHeight: number) => {
      const handleMouseMove = (e: MouseEvent) => {
        const delta = e.clientY - startY
        const newH = Math.max(MIN_ROW_HEIGHT, currentHeight + delta)
        setRowHeightOverrides((prev) => {
          const next = new Map(prev)
          next.set(rowIndex, newH)
          return next
        })
      }

      const handleMouseUp = () => {
        document.removeEventListener('mousemove', handleMouseMove)
        document.removeEventListener('mouseup', handleMouseUp)
        document.body.style.cursor = ''
        document.body.style.userSelect = ''
      }

      document.body.style.cursor = 'row-resize'
      document.body.style.userSelect = 'none'
      document.addEventListener('mousemove', handleMouseMove)
      document.addEventListener('mouseup', handleMouseUp)
    },
    [],
  )

  const isBoxZone = zone.zone_type === 'box'
  const numCols = zone.columns.length

  const gridTemplateCols = `${ROW_NUM_WIDTH}px ${effectiveColWidths.map((w) => `${w.toFixed(1)}px`).join(' ')}`

  return (
    <div
      ref={containerRef}
      className={`overflow-x-auto ${isBoxZone ? 'border-2 border-gray-400 dark:border-gray-500 rounded-lg' : ''}`}
    >
      {/* Zone label */}
      <div className="flex items-center gap-2 px-2 py-1 text-xs text-gray-500 dark:text-gray-400">
        <span
          className={`inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-medium ${
            isBoxZone
              ? 'bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 border border-amber-200 dark:border-amber-800'
              : 'bg-gray-50 dark:bg-gray-800 text-gray-500 dark:text-gray-400 border border-gray-200 dark:border-gray-700'
          }`}
        >
          {isBoxZone ? 'Box' : 'Inhalt'} Zone {zone.zone_index}
        </span>
        <span>
          {zone.columns.length} Spalten, {zone.rows.length} Zeilen, {zone.cells.length} Zellen
        </span>
      </div>

      {/* CSS Grid */}
      <div
        style={{
          display: 'grid',
          gridTemplateColumns: gridTemplateCols,
          fontFamily: "var(--font-noto-sans, 'Noto Sans'), 'Inter', system-ui, sans-serif",
          fontSize: `${baseFontSize}px`,
        }}
      >
        {/* Header: row-number corner */}
        <div className="sticky left-0 z-10 px-1 py-1.5 text-[10px] text-gray-400 dark:text-gray-500 border-b border-r border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50" />

        {/* Header: column labels */}
        {zone.columns.map((col, ci) => (
          <GridTableColumnHeader
            key={col.index}
            col={col}
            colIndex={ci}
            numCols={numCols}
            zoneIndex={zone.zone_index}
            onToggleColumnBold={onToggleColumnBold}
            onDeleteColumn={onDeleteColumn}
            onAddColumn={onAddColumn}
            onColResizeStart={handleColResizeStart}
          />
        ))}

        {/* Data rows */}
        {zone.rows.map((row) => {
          const rowH = computeRowHeight(row.index, row.is_header)
          const isSpanning = zone.cells.some(
            (c) => c.row_index === row.index && c.col_type === 'spanning_header',
          )

          return (
            <div key={row.index} style={{ display: 'contents' }}>
              {/* Row number cell */}
              <GridTableRowHeader
                row={row}
                zoneIndex={zone.zone_index}
                rowCount={zone.rows.length}
                rowH={rowH}
                onToggleRowHeader={onToggleRowHeader}
                onDeleteRow={onDeleteRow}
                onAddRow={onAddRow}
                onRowResizeStart={handleRowResizeStart}
              />

              {/* Cells — spanning header or normal columns */}
              {isSpanning ? (
                <>
                  {zone.cells
                    .filter((c) => c.row_index === row.index && c.col_type === 'spanning_header')
                    .sort((a, b) => a.col_index - b.col_index)
                    .map((spanCell) => {
                      const colspan = spanCell.colspan || numCols
                      const cellId = spanCell.cell_id
                      const isSelected = selectedCell === cellId
                      const cellColor = getCellColor(spanCell)
                      const gridColStart = spanCell.col_index + 2
                      const gridColEnd = gridColStart + colspan
                      return (
                        <div
                          key={cellId}
                          className={`border-b border-r border-gray-200 dark:border-gray-700 bg-blue-50/50 dark:bg-blue-900/10 flex items-center ${
                            isSelected ? 'ring-2 ring-teal-500 ring-inset z-10' : ''
                          }`}
                          style={{ gridColumn: `${gridColStart} / ${gridColEnd}`, height: `${rowH}px` }}
                        >
                          {cellColor && (
                            <span className="flex-shrink-0 w-1.5 self-stretch rounded-l-sm" style={{ backgroundColor: cellColor }} />
                          )}
                          <input
                            id={`cell-${cellId}`}
                            type="text"
                            value={spanCell.text}
                            onChange={(e) => onCellTextChange(cellId, e.target.value)}
                            onFocus={() => onSelectCell(cellId)}
                            onKeyDown={(e) => handleKeyDown(e, cellId)}
                            className="w-full px-3 py-1 bg-transparent border-0 outline-none text-center"
                            style={{ color: cellColor || undefined }}
                            spellCheck={false}
                          />
                        </div>
                      )
                    })}
                </>
              ) : (
                zone.columns.map((col) => {
                  const cell = cellMap.get(`${row.index}_${col.index}`)
                  return (
                    <GridTableCell
                      key={col.index}
                      cell={cell}
                      col={col}
                      row={row}
                      zone={zone}
                      rowH={rowH}
                      selectedCell={selectedCell}
                      selectedCells={selectedCells}
                      onSelectCell={onSelectCell}
                      onToggleCellSelection={onToggleCellSelection}
                      onCellTextChange={onCellTextChange}
                      onNavigate={onNavigate}
                      onSetCellColor={onSetCellColor}
                      onOpenColorMenu={(cellId, x, y) => setColorMenu({ cellId, x, y })}
                      handleKeyDown={handleKeyDown}
                    />
                  )
                })
              )}
            </div>
          )
        })}
      </div>

      {/* Color context menu (right-click) */}
      {colorMenu && onSetCellColor && (
        <GridTableColorMenu
          cellId={colorMenu.cellId}
          x={colorMenu.x}
          y={colorMenu.y}
          onSetCellColor={onSetCellColor}
          onClose={() => setColorMenu(null)}
        />
      )}
    </div>
  )
}
