'use client'

import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import dynamic from 'next/dynamic'
import { usePixelWordPositions } from './usePixelWordPositions'
import type { EditableCell, UndoAction, StepReconstructionProps } from './StepReconstructionTypes'
import { KLAUSUR_API } from './StepReconstructionTypes'
import { useReconstructionData } from './useReconstructionData'
import { ReconstructionToolbar } from './ReconstructionToolbar'
import { ReconstructionOverlay } from './ReconstructionOverlay'
import { ReconstructionSimpleView } from './ReconstructionSimpleView'

// Lazy-load Fabric.js canvas editor (SSR-incompatible)
const FabricReconstructionCanvas = dynamic(
  () => import('./FabricReconstructionCanvas').then(m => ({ default: m.FabricReconstructionCanvas })),
  { ssr: false, loading: () => <div className="py-8 text-center text-sm text-gray-400">Editor wird geladen...</div> }
)

export function StepReconstruction({ sessionId, onNext }: StepReconstructionProps) {
  const [editedTexts, setEditedTexts] = useState<Map<string, string>>(new Map())
  const [zoom, setZoom] = useState(100)
  const [imageNaturalH, setImageNaturalH] = useState(0)
  const [showEmptyHighlight, setShowEmptyHighlight] = useState(true)
  const [fontScale, setFontScale] = useState(0.7)
  const [globalBold, setGlobalBold] = useState(false)
  const [showStructure, setShowStructure] = useState(true)
  const [undoStack, setUndoStack] = useState<UndoAction[]>([])
  const [redoStack, setRedoStack] = useState<UndoAction[]>([])

  const imageRef = useRef<HTMLImageElement>(null)

  const resetEditing = useCallback(() => {
    setEditedTexts(new Map())
    setUndoStack([])
    setRedoStack([])
  }, [])

  const data = useReconstructionData(sessionId, resetEditing)

  // Pixel-based word positions for overlay mode
  const overlayImageUrl = sessionId
    ? `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/cropped`
    : ''
  const cellWordPositions = usePixelWordPositions(
    overlayImageUrl,
    data.mergedGridCells,
    data.editorMode === 'overlay',
    data.imageRotation,
  )

  // Track image natural dimensions for font scaling and structure layer
  const handleImageLoad = useCallback(() => {
    if (imageRef.current) {
      setImageNaturalH(imageRef.current.naturalHeight)
      if (!data.imageNaturalSize) {
        data.setImageNaturalSize({ w: imageRef.current.naturalWidth, h: imageRef.current.naturalHeight })
      }
    }
  }, [data])

  // --- Cell editing callbacks ---

  const handleTextChange = useCallback((cellId: string, newText: string) => {
    setEditedTexts(prev => {
      const oldText = prev.get(cellId)
      const cell = data.cells.find(c => c.cellId === cellId)
      const prevText = oldText ?? cell?.text ?? ''
      setUndoStack(stack => [...stack, { cellId, oldText: prevText, newText }])
      setRedoStack([])
      const next = new Map(prev)
      next.set(cellId, newText)
      return next
    })
  }, [data.cells])

  const undo = useCallback(() => {
    setUndoStack(stack => {
      if (stack.length === 0) return stack
      const action = stack[stack.length - 1]
      setRedoStack(rs => [...rs, action])
      setEditedTexts(prev => {
        const next = new Map(prev)
        next.set(action.cellId, action.oldText)
        return next
      })
      return stack.slice(0, -1)
    })
  }, [])

  const redo = useCallback(() => {
    setRedoStack(stack => {
      if (stack.length === 0) return stack
      const action = stack[stack.length - 1]
      setUndoStack(us => [...us, action])
      setEditedTexts(prev => {
        const next = new Map(prev)
        next.set(action.cellId, action.newText)
        return next
      })
      return stack.slice(0, -1)
    })
  }, [])

  const resetCell = useCallback((cellId: string) => {
    const cell = data.cells.find(c => c.cellId === cellId)
    if (!cell) return
    setEditedTexts(prev => { const next = new Map(prev); next.delete(cellId); return next })
  }, [data.cells])

  // Global keyboard shortcuts for undo/redo
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'z') {
        e.preventDefault()
        if (e.shiftKey) { redo() } else { undo() }
      }
    }
    document.addEventListener('keydown', handler)
    return () => document.removeEventListener('keydown', handler)
  }, [undo, redo])

  const getDisplayText = useCallback((cell: EditableCell): string => {
    return editedTexts.get(cell.cellId) ?? cell.text
  }, [editedTexts])

  const isEdited = useCallback((cell: EditableCell): boolean => {
    const edited = editedTexts.get(cell.cellId)
    return edited !== undefined && edited !== cell.originalText
  }, [editedTexts])

  const changedCount = useMemo(() => {
    let count = 0
    for (const cell of data.cells) { if (isEdited(cell)) count++ }
    return count
  }, [data.cells, isEdited])

  const emptyCellIds = useMemo(() => {
    const required = new Set(['column_en', 'column_de'])
    const ids = new Set<string>()
    for (const cell of data.cells) {
      if (required.has(cell.colType) && !cell.text.trim()) ids.add(cell.cellId)
    }
    return ids
  }, [data.cells])

  const sortedCellIds = useMemo(() => {
    return [...data.cells]
      .sort((a, b) => a.rowIndex !== b.rowIndex ? a.rowIndex - b.rowIndex : a.colIndex - b.colIndex)
      .map(c => c.cellId)
  }, [data.cells])

  const handleKeyDown = useCallback((e: React.KeyboardEvent, cellId: string) => {
    if (e.key === 'Tab') {
      e.preventDefault()
      const idx = sortedCellIds.indexOf(cellId)
      const nextIdx = e.shiftKey ? idx - 1 : idx + 1
      if (nextIdx >= 0 && nextIdx < sortedCellIds.length) {
        document.getElementById(`cell-${sortedCellIds[nextIdx]}`)?.focus()
      }
    }
  }, [sortedCellIds])

  const saveReconstruction = useCallback(async () => {
    if (!sessionId) return
    data.setStatus('saving')
    try {
      const cellUpdates = Array.from(editedTexts.entries())
        .filter(([cellId, text]) => {
          const cell = data.cells.find(c => c.cellId === cellId)
          return cell && text !== cell.originalText
        })
        .map(([cellId, text]) => ({ cell_id: cellId, text }))

      if (cellUpdates.length === 0) { data.setStatus('saved'); return }

      const res = await fetch(`${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/reconstruction`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ cells: cellUpdates }),
      })
      if (!res.ok) {
        const d = await res.json().catch(() => ({}))
        throw new Error(d.detail || `HTTP ${res.status}`)
      }
      data.setStatus('saved')
    } catch (e: unknown) {
      data.setError(e instanceof Error ? e.message : String(e))
      data.setStatus('error')
    }
  }, [sessionId, editedTexts, data])

  const handleFabricCellsChanged = useCallback((updates: { cell_id: string; text: string }[]) => {
    for (const u of updates) {
      setEditedTexts(prev => { const next = new Map(prev); next.set(u.cell_id, u.text); return next })
    }
  }, [])

  const boxZonesPct = useMemo(() =>
    data.parentZones
      .filter(z => z.zone_type === 'box' && z.box)
      .map(z => {
        const imgH = data.imageNaturalSize?.h || 1
        return {
          topPct: (z.box!.y / imgH) * 100,
          bottomPct: ((z.box!.y + z.box!.height) / imgH) * 100,
        }
      }),
    [data.parentZones, data.imageNaturalSize]
  )

  const dewarpedUrl = sessionId
    ? `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/cropped`
    : ''

  const hasStructureElements = data.structureBoxes.length > 0 || data.structureGraphics.length > 0

  // --- Status screens ---

  if (!sessionId) {
    return <div className="text-center py-12 text-gray-400">Bitte zuerst eine Session auswaehlen.</div>
  }
  if (data.status === 'loading') {
    return (
      <div className="flex items-center gap-3 justify-center py-12">
        <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-teal-500" />
        <span className="text-gray-500">Rekonstruktionsdaten werden geladen...</span>
      </div>
    )
  }
  if (data.status === 'error') {
    return (
      <div className="flex flex-col items-center justify-center py-12 text-center">
        <div className="text-5xl mb-4">&#x26A0;&#xFE0F;</div>
        <h3 className="text-lg font-medium text-red-600 dark:text-red-400 mb-2">Fehler</h3>
        <p className="text-sm text-gray-500 dark:text-gray-400 max-w-lg mb-4">{data.error}</p>
        <div className="flex gap-3">
          <button onClick={() => { data.setError(''); data.loadSessionData() }}
            className="px-5 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 transition-colors text-sm">
            Erneut versuchen
          </button>
          <button onClick={onNext}
            className="px-5 py-2 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors text-sm">
            Ueberspringen &rarr;
          </button>
        </div>
      </div>
    )
  }
  if (data.status === 'saved') {
    return (
      <div className="flex flex-col items-center justify-center py-12 text-center">
        <div className="text-5xl mb-4">&#x2705;</div>
        <h3 className="text-lg font-medium text-gray-700 dark:text-gray-300 mb-2">Rekonstruktion gespeichert</h3>
        <p className="text-sm text-gray-500 dark:text-gray-400 mb-6">
          {changedCount > 0 ? `${changedCount} Zellen wurden aktualisiert.` : 'Keine Aenderungen vorgenommen.'}
        </p>
        <button onClick={onNext}
          className="px-6 py-2.5 bg-teal-600 text-white rounded-lg hover:bg-teal-700 transition-colors font-medium">
          Weiter &rarr;
        </button>
      </div>
    )
  }

  // --- Main rendering ---

  return (
    <div className="space-y-3">
      <ReconstructionToolbar
        editorMode={data.editorMode}
        setEditorMode={data.setEditorMode}
        isParentWithBoxes={data.isParentWithBoxes}
        cellCount={data.cells.length}
        changedCount={changedCount}
        emptyCellCount={emptyCellIds.size}
        showEmptyHighlight={showEmptyHighlight}
        setShowEmptyHighlight={setShowEmptyHighlight}
        showStructure={showStructure}
        setShowStructure={setShowStructure}
        hasStructureElements={hasStructureElements}
        zoom={zoom}
        setZoom={setZoom}
        undoCount={undoStack.length}
        redoCount={redoStack.length}
        onUndo={undo}
        onRedo={redo}
        status={data.status}
        onSave={saveReconstruction}
        fontScale={fontScale}
        setFontScale={setFontScale}
        globalBold={globalBold}
        setGlobalBold={setGlobalBold}
        imageRotation={data.imageRotation}
        setImageRotation={data.setImageRotation}
      />

      {data.editorMode === 'overlay' ? (
        <ReconstructionOverlay
          cells={data.cells}
          dewarpedUrl={dewarpedUrl}
          imageNaturalSize={data.imageNaturalSize}
          parentColumns={data.parentColumns}
          parentRows={data.parentRows}
          parentZones={data.parentZones}
          structureBoxes={data.structureBoxes}
          structureGraphics={data.structureGraphics}
          showStructure={showStructure}
          fontScale={fontScale}
          globalBold={globalBold}
          boxZonesPct={boxZonesPct}
          cellWordPositions={cellWordPositions}
          onTextChange={handleTextChange}
          onKeyDown={handleKeyDown}
          onResetCell={resetCell}
          onImageNaturalSize={data.setImageNaturalSize}
          getDisplayText={getDisplayText}
          isEdited={isEdited}
        />
      ) : data.editorMode === 'editor' && sessionId ? (
        <FabricReconstructionCanvas
          sessionId={sessionId}
          cells={data.gridCells}
          onCellsChanged={handleFabricCellsChanged}
        />
      ) : (
        <ReconstructionSimpleView
          cells={data.cells}
          dewarpedUrl={dewarpedUrl}
          zoom={zoom}
          imageNaturalSize={data.imageNaturalSize}
          imageNaturalH={imageNaturalH}
          emptyCellIds={emptyCellIds}
          showEmptyHighlight={showEmptyHighlight}
          structureBoxes={data.structureBoxes}
          structureGraphics={data.structureGraphics}
          showStructure={showStructure}
          onTextChange={handleTextChange}
          onKeyDown={handleKeyDown}
          onResetCell={resetCell}
          onImageLoad={handleImageLoad}
          getDisplayText={getDisplayText}
          isEdited={isEdited}
          imageRef={imageRef}
        />
      )}

      <div className="flex justify-end">
        <button
          onClick={() => { changedCount > 0 ? saveReconstruction() : onNext() }}
          className="px-6 py-2.5 bg-teal-600 text-white rounded-lg hover:bg-teal-700 transition-colors font-medium text-sm"
        >
          {changedCount > 0 ? 'Speichern & Weiter \u2192' : 'Weiter \u2192'}
        </button>
      </div>
    </div>
  )
}
