'use client'

import { useCallback, useEffect, useRef, useState } from 'react'
import type { GridZone, LayoutMetrics } from './types'

interface GridTableProps {
  zone: GridZone
  layoutMetrics?: LayoutMetrics
  selectedCell: string | null
  onSelectCell: (cellId: string) => void
  onCellTextChange: (cellId: string, text: string) => void
  onToggleColumnBold: (zoneIndex: number, colIndex: number) => void
  onToggleRowHeader: (zoneIndex: number, rowIndex: number) => void
  onNavigate: (cellId: string, direction: 'up' | 'down' | 'left' | 'right') => void
}

/** Gutter width for row numbers (px). */
const ROW_NUM_WIDTH = 36

/** Minimum column width in px so columns remain usable. */
const MIN_COL_WIDTH = 40

/** Minimum row height in px. */
const MIN_ROW_HEIGHT = 26

export function GridTable({
  zone,
  layoutMetrics,
  selectedCell,
  onSelectCell,
  onCellTextChange,
  onToggleColumnBold,
  onToggleRowHeader,
  onNavigate,
}: GridTableProps) {
  const containerRef = useRef<HTMLDivElement>(null)
  const [containerWidth, setContainerWidth] = useState(0)

  // ----------------------------------------------------------------
  // 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
  // ----------------------------------------------------------------
  // Use the actual total column span as reference width — NOT zone.bbox_px.w.
  // When union columns are applied across content zones, column boundaries
  // can extend beyond the zone's bbox, causing overflow if we scale by
  // the smaller zone width.
  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),
  )

  // ----------------------------------------------------------------
  // Compute row heights from OCR measurements
  // ----------------------------------------------------------------
  const avgRowHeightPx = layoutMetrics?.avg_row_height_px ?? 30
  const [rowHeightOverrides, setRowHeightOverrides] = useState<Map<number, number>>(new Map())

  const getRowHeight = (rowIndex: number, isHeader: boolean): number => {
    if (rowHeightOverrides.has(rowIndex)) {
      return rowHeightOverrides.get(rowIndex)!
    }
    const row = zone.rows.find((r) => r.index === rowIndex)
    if (!row) return Math.max(MIN_ROW_HEIGHT, avgRowHeightPx * scale)

    if (isHeader) {
      // Headers keep their measured height
      const measuredH = row.y_max_px - row.y_min_px
      return Math.max(MIN_ROW_HEIGHT, measuredH * scale)
    }
    // Content rows use average for uniformity
    return Math.max(MIN_ROW_HEIGHT, 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.altKey) {
        e.preventDefault()
        onNavigate(cellId, 'up')
      } else if (e.key === 'ArrowDown' && e.altKey) {
        e.preventDefault()
        onNavigate(cellId, 'down')
      } else if (e.key === 'Escape') {
        ;(e.target as HTMLElement).blur()
      }
    },
    [onNavigate],
  )

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

  /** Dominant non-black color from a cell's word_boxes, or null. */
  const getCellColor = (cell: (typeof zone.cells)[0] | undefined): string | null => {
    if (!cell?.word_boxes?.length) return null
    for (const wb of cell.word_boxes) {
      if (wb.color_name && wb.color_name !== 'black' && wb.color) {
        return wb.color
      }
    }
    return null
  }

  // ----------------------------------------------------------------
  // 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)
        // Steal from next column to keep total constant
        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

  // CSS Grid template for columns: row-number gutter + proportional columns
  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 — column headers                                     */}
      {/* ============================================================ */}
      <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 with resize handles */}
        {zone.columns.map((col, ci) => (
          <div
            key={col.index}
            className={`relative px-2 py-1.5 text-xs font-medium border-b border-r border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 cursor-pointer select-none transition-colors hover:bg-gray-100 dark:hover:bg-gray-700 ${
              col.bold ? 'text-teal-700 dark:text-teal-300' : 'text-gray-600 dark:text-gray-400'
            }`}
            onClick={() => onToggleColumnBold(zone.zone_index, col.index)}
            title={`Spalte ${col.index + 1} — Klick fuer Fett-Toggle`}
          >
            <div className="flex items-center gap-1 justify-center truncate">
              <span>{col.label}</span>
              {col.bold && (
                <span className="text-[9px] px-1 py-0 rounded bg-teal-100 dark:bg-teal-900/40 text-teal-600 dark:text-teal-400">
                  B
                </span>
              )}
            </div>
            {/* Right-edge resize handle */}
            {ci < numCols - 1 && (
              <div
                className="absolute top-0 right-0 w-[5px] h-full cursor-col-resize hover:bg-teal-400/40 z-20"
                onMouseDown={(e) => {
                  e.stopPropagation()
                  handleColResizeStart(ci, e.clientX)
                }}
              />
            )}
          </div>
        ))}

        {/* ============================================================ */}
        {/* Data rows                                                     */}
        {/* ============================================================ */}
        {zone.rows.map((row) => {
          const rowH = getRowHeight(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 */}
              <div
                className={`relative sticky left-0 z-10 flex items-center justify-center text-[10px] border-b border-r border-gray-200 dark:border-gray-700 cursor-pointer select-none transition-colors hover:bg-gray-100 dark:hover:bg-gray-700 ${
                  row.is_header
                    ? 'bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-medium'
                    : row.is_footer
                    ? 'bg-amber-50 dark:bg-amber-900/20 text-amber-600 dark:text-amber-400 font-medium'
                    : 'bg-gray-50 dark:bg-gray-800/50 text-gray-400 dark:text-gray-500'
                }`}
                style={{ height: `${rowH}px` }}
                onClick={() => onToggleRowHeader(zone.zone_index, row.index)}
                title={`Zeile ${row.index + 1} — Klick fuer Header-Toggle`}
              >
                {row.index + 1}
                {row.is_header && <span className="block text-[8px]">H</span>}
                {row.is_footer && <span className="block text-[8px]">F</span>}
                {/* Bottom-edge resize handle */}
                <div
                  className="absolute bottom-0 left-0 w-full h-[4px] cursor-row-resize hover:bg-teal-400/40 z-20"
                  onMouseDown={(e) => {
                    e.stopPropagation()
                    handleRowResizeStart(row.index, e.clientY, rowH)
                  }}
                />
              </div>

              {/* Cells — spanning header or normal columns */}
              {isSpanning ? (
                <div
                  className="border-b border-r border-gray-200 dark:border-gray-700 bg-blue-50/50 dark:bg-blue-900/10 flex items-center"
                  style={{
                    gridColumn: `2 / ${numCols + 2}`,
                    height: `${rowH}px`,
                  }}
                >
                  {(() => {
                    const spanCell = zone.cells.find(
                      (c) => c.row_index === row.index && c.col_type === 'spanning_header',
                    )
                    if (!spanCell) return null
                    const cellId = spanCell.cell_id
                    const isSelected = selectedCell === cellId
                    const cellColor = getCellColor(spanCell)
                    return (
                      <div className="flex items-center w-full">
                        {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 ${
                            isSelected ? 'ring-2 ring-teal-500 ring-inset rounded' : ''
                          }`}
                          style={{ color: cellColor || undefined }}
                          spellCheck={false}
                        />
                      </div>
                    )
                  })()}
                </div>
              ) : (
                zone.columns.map((col) => {
                  const cell = cellMap.get(`${row.index}_${col.index}`)
                  const cellId =
                    cell?.cell_id ??
                    `Z${zone.zone_index}_R${String(row.index).padStart(2, '0')}_C${col.index}`
                  const isSelected = selectedCell === cellId
                  const isBold = col.bold || cell?.is_bold
                  const isLowConf = cell && cell.confidence > 0 && cell.confidence < 60
                  const cellColor = getCellColor(cell)
                  // Show per-word colored display only when word_boxes
                  // match the cell text.  Post-processing steps (e.g. 5h
                  // slash-IPA → bracket conversion) modify cell.text but
                  // not individual word_boxes, so we fall back to the
                  // plain input when they diverge.
                  const wbText = cell?.word_boxes?.map((wb) => wb.text).join(' ') ?? ''
                  const textMatches = !cell?.text || wbText === cell.text
                  const hasColoredWords =
                    textMatches &&
                    (cell?.word_boxes?.some(
                      (wb) => wb.color_name && wb.color_name !== 'black',
                    ) ?? false)

                  return (
                    <div
                      key={col.index}
                      className={`relative border-b border-r border-gray-200 dark:border-gray-700 flex items-center ${
                        isSelected ? 'ring-2 ring-teal-500 ring-inset z-10' : ''
                      } ${isLowConf ? 'bg-amber-50/50 dark:bg-amber-900/10' : ''} ${
                        row.is_header ? 'bg-blue-50/50 dark:bg-blue-900/10' : ''
                      }`}
                      style={{ height: `${rowH}px` }}
                    >
                      {cellColor && (
                        <span
                          className="flex-shrink-0 w-1.5 self-stretch rounded-l-sm"
                          style={{ backgroundColor: cellColor }}
                          title={`Farbe: ${cell?.word_boxes?.find((wb) => wb.color_name !== 'black')?.color_name}`}
                        />
                      )}
                      {/* Per-word colored display when not editing */}
                      {hasColoredWords && !isSelected ? (
                        <div
                          className={`w-full px-2 cursor-text truncate ${isBold ? 'font-bold' : 'font-normal'}`}
                          onClick={() => {
                            onSelectCell(cellId)
                            setTimeout(() => document.getElementById(`cell-${cellId}`)?.focus(), 0)
                          }}
                        >
                          {cell!.word_boxes!.map((wb, i) => (
                            <span
                              key={i}
                              style={
                                wb.color_name && wb.color_name !== 'black'
                                  ? { color: wb.color }
                                  : undefined
                              }
                            >
                              {wb.text}
                              {i < cell!.word_boxes!.length - 1 ? ' ' : ''}
                            </span>
                          ))}
                        </div>
                      ) : (
                        <input
                          id={`cell-${cellId}`}
                          type="text"
                          value={cell?.text ?? ''}
                          onChange={(e) => {
                            if (cell) onCellTextChange(cellId, e.target.value)
                          }}
                          onFocus={() => onSelectCell(cellId)}
                          onKeyDown={(e) => handleKeyDown(e, cellId)}
                          className={`w-full px-2 bg-transparent border-0 outline-none ${
                            isBold ? 'font-bold' : 'font-normal'
                          }`}
                          spellCheck={false}
                        />
                      )}
                    </div>
                  )
                })
              )}
            </div>
          )
        })}
      </div>
    </div>
  )
}
