'use client'

import { useCallback, useEffect, useRef, useState } from 'react'
import type { GridCell } from '@/app/(admin)/ai/ocr-pipeline/types'

const KLAUSUR_API = '/klausur-api'

// Column type → colour mapping
const COL_TYPE_COLORS: Record<string, string> = {
  column_en: '#3b82f6',      // blue-500
  column_de: '#22c55e',      // green-500
  column_example: '#f97316', // orange-500
  column_text: '#a855f7',    // purple-500
  page_ref: '#06b6d4',       // cyan-500
  column_marker: '#6b7280',  // gray-500
}

interface FabricReconstructionCanvasProps {
  sessionId: string
  cells: GridCell[]
  onCellsChanged: (updates: { cell_id: string; text: string }[]) => void
}

// Fabric.js types (subset used here)
interface FabricCanvas {
  add: (...objects: FabricObject[]) => FabricCanvas
  remove: (...objects: FabricObject[]) => FabricCanvas
  setBackgroundImage: (img: FabricImage, callback: () => void) => void
  renderAll: () => void
  getObjects: () => FabricObject[]
  dispose: () => void
  on: (event: string, handler: (e: FabricEvent) => void) => void
  setWidth: (w: number) => void
  setHeight: (h: number) => void
  getActiveObject: () => FabricObject | null
  discardActiveObject: () => FabricCanvas
  requestRenderAll: () => void
  setZoom: (z: number) => void
  getZoom: () => number
}

interface FabricObject {
  type?: string
  left?: number
  top?: number
  width?: number
  height?: number
  text?: string
  set: (props: Record<string, unknown>) => FabricObject
  get: (prop: string) => unknown
  data?: Record<string, unknown>
  selectable?: boolean
  on?: (event: string, handler: () => void) => void
  setCoords?: () => void
}

interface FabricImage extends FabricObject {
  width?: number
  height?: number
  scaleX?: number
  scaleY?: number
}

interface FabricEvent {
  target?: FabricObject
  e?: MouseEvent
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type FabricModule = any

export function FabricReconstructionCanvas({
  sessionId,
  cells,
  onCellsChanged,
}: FabricReconstructionCanvasProps) {
  const canvasElRef = useRef<HTMLCanvasElement>(null)
  const fabricRef = useRef<FabricCanvas | null>(null)
  const fabricModuleRef = useRef<FabricModule>(null)
  const [ready, setReady] = useState(false)
  const [opacity, setOpacity] = useState(30)
  const [zoom, setZoom] = useState(100)
  const [selectedCell, setSelectedCell] = useState<string | null>(null)
  const [error, setError] = useState('')

  // Undo/Redo
  const undoStackRef = useRef<{ cellId: string; oldText: string; newText: string }[]>([])
  const redoStackRef = useRef<{ cellId: string; oldText: string; newText: string }[]>([])

  // ---- Initialise Fabric.js ----
  useEffect(() => {
    let disposed = false

    async function init() {
      try {
        const fabricModule = await import('fabric')
        if (disposed) return
        fabricModuleRef.current = fabricModule

        const canvasEl = canvasElRef.current
        if (!canvasEl) return

        // Load background image first to get dimensions
        const imgUrl = `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/dewarped`

        const bgImg = await fabricModule.FabricImage.fromURL(imgUrl, { crossOrigin: 'anonymous' }) as FabricImage

        if (disposed) return

        const imgW = (bgImg.width || 800) * (bgImg.scaleX || 1)
        const imgH = (bgImg.height || 600) * (bgImg.scaleY || 1)

        bgImg.set({ opacity: opacity / 100, selectable: false, evented: false } as Record<string, unknown>)

        const canvas = new fabricModule.Canvas(canvasEl, {
          width: imgW,
          height: imgH,
          selection: true,
          preserveObjectStacking: true,
          backgroundImage: bgImg,
        }) as unknown as FabricCanvas

        fabricRef.current = canvas
        canvas.renderAll()

        // Add cell objects
        addCellObjects(canvas, fabricModule, cells, imgW, imgH)

        // Listen for text changes
        canvas.on('object:modified', (e: FabricEvent) => {
          if (e.target?.data?.cellId) {
            const cellId = e.target.data.cellId as string
            const newText = (e.target.text || '') as string
            onCellsChanged([{ cell_id: cellId, text: newText }])
          }
        })

        // Selection tracking
        canvas.on('selection:created', (e: FabricEvent) => {
          if (e.target?.data?.cellId) setSelectedCell(e.target.data.cellId as string)
        })
        canvas.on('selection:updated', (e: FabricEvent) => {
          if (e.target?.data?.cellId) setSelectedCell(e.target.data.cellId as string)
        })
        canvas.on('selection:cleared', () => setSelectedCell(null))

        setReady(true)
      } catch (err) {
        if (!disposed) setError(err instanceof Error ? err.message : 'Fabric.js konnte nicht geladen werden')
      }
    }

    init()

    return () => {
      disposed = true
      fabricRef.current?.dispose()
      fabricRef.current = null
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sessionId])

  function addCellObjects(
    canvas: FabricCanvas,
    fabricModule: FabricModule,
    gridCells: GridCell[],
    imgW: number,
    imgH: number,
  ) {
    for (const cell of gridCells) {
      const color = COL_TYPE_COLORS[cell.col_type] || '#6b7280'
      const x = (cell.bbox_pct.x / 100) * imgW
      const y = (cell.bbox_pct.y / 100) * imgH
      const w = (cell.bbox_pct.w / 100) * imgW
      const h = (cell.bbox_pct.h / 100) * imgH

      const fontSize = Math.max(8, Math.min(18, h * 0.55))

      const textObj = new fabricModule.IText(cell.text || '', {
        left: x,
        top: y,
        width: w,
        fontSize,
        fontFamily: 'monospace',
        fill: '#000000',
        backgroundColor: `${color}22`,
        padding: 2,
        editable: true,
        selectable: true,
        lockScalingFlip: true,
        data: {
          cellId: cell.cell_id,
          colType: cell.col_type,
          rowIndex: cell.row_index,
          colIndex: cell.col_index,
          originalText: cell.text,
        },
      })

      // Border colour matches column type
      textObj.set({
        borderColor: color,
        cornerColor: color,
        cornerSize: 6,
        transparentCorners: false,
      } as Record<string, unknown>)

      canvas.add(textObj)
    }
    canvas.renderAll()
  }

  // ---- Opacity slider ----
  const handleOpacityChange = useCallback((val: number) => {
    setOpacity(val)
    const canvas = fabricRef.current
    if (!canvas) return
    // Fabric v6: backgroundImage is a direct property on the canvas
    const bgImg = (canvas as unknown as { backgroundImage?: FabricObject }).backgroundImage
    if (bgImg) {
      bgImg.set({ opacity: val / 100 })
      canvas.renderAll()
    }
  }, [])

  // ---- Zoom ----
  const handleZoomChange = useCallback((val: number) => {
    setZoom(val)
    const canvas = fabricRef.current
    if (!canvas) return
    ;(canvas as unknown as { zoom: number }).zoom = val / 100
    canvas.requestRenderAll()
  }, [])

  // ---- Undo / Redo via keyboard ----
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if (!(e.metaKey || e.ctrlKey) || e.key !== 'z') return
      e.preventDefault()

      const canvas = fabricRef.current
      if (!canvas) return

      if (e.shiftKey) {
        // Redo
        const action = redoStackRef.current.pop()
        if (!action) return
        undoStackRef.current.push(action)
        const obj = canvas.getObjects().find(
          (o: FabricObject) => o.data?.cellId === action.cellId
        )
        if (obj) {
          obj.set({ text: action.newText } as Record<string, unknown>)
          canvas.renderAll()
          onCellsChanged([{ cell_id: action.cellId, text: action.newText }])
        }
      } else {
        // Undo
        const action = undoStackRef.current.pop()
        if (!action) return
        redoStackRef.current.push(action)
        const obj = canvas.getObjects().find(
          (o: FabricObject) => o.data?.cellId === action.cellId
        )
        if (obj) {
          obj.set({ text: action.oldText } as Record<string, unknown>)
          canvas.renderAll()
          onCellsChanged([{ cell_id: action.cellId, text: action.oldText }])
        }
      }
    }
    document.addEventListener('keydown', handler)
    return () => document.removeEventListener('keydown', handler)
  }, [onCellsChanged])

  // ---- Delete selected cell (via context-menu or Delete key) ----
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if (e.key !== 'Delete' && e.key !== 'Backspace') return
      // Only delete if not currently editing text inside an IText
      const canvas = fabricRef.current
      if (!canvas) return
      const active = canvas.getActiveObject()
      if (!active) return
      // If the IText is in editing mode, let the keypress pass through
      if ((active as unknown as Record<string, boolean>).isEditing) return
      e.preventDefault()
      canvas.remove(active)
      canvas.discardActiveObject()
      canvas.renderAll()
    }
    document.addEventListener('keydown', handler)
    return () => document.removeEventListener('keydown', handler)
  }, [])

  // ---- Export helpers ----
  const handleExportPdf = useCallback(() => {
    window.open(
      `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/reconstruction/export/pdf`,
      '_blank'
    )
  }, [sessionId])

  const handleExportDocx = useCallback(() => {
    window.open(
      `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/reconstruction/export/docx`,
      '_blank'
    )
  }, [sessionId])

  if (error) {
    return (
      <div className="flex flex-col items-center justify-center py-8 text-red-500 text-sm">
        <p>Fabric.js Editor konnte nicht geladen werden:</p>
        <p className="text-xs mt-1 text-gray-400">{error}</p>
      </div>
    )
  }

  return (
    <div className="space-y-2">
      {/* Toolbar */}
      <div className="flex items-center gap-3 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 px-3 py-2 text-xs">
        {/* Opacity slider */}
        <label className="flex items-center gap-1.5 text-gray-500">
          Hintergrund
          <input
            type="range"
            min={0} max={100}
            value={opacity}
            onChange={e => handleOpacityChange(Number(e.target.value))}
            className="w-20 h-1 accent-teal-500"
          />
          <span className="w-8 text-right">{opacity}%</span>
        </label>

        <div className="w-px h-5 bg-gray-300 dark:bg-gray-600" />

        {/* Zoom */}
        <label className="flex items-center gap-1.5 text-gray-500">
          Zoom
          <button onClick={() => handleZoomChange(Math.max(25, zoom - 25))}
            className="px-1.5 py-0.5 border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700">
            &minus;
          </button>
          <span className="w-8 text-center">{zoom}%</span>
          <button onClick={() => handleZoomChange(Math.min(200, zoom + 25))}
            className="px-1.5 py-0.5 border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700">
            +
          </button>
          <button onClick={() => handleZoomChange(100)}
            className="px-1.5 py-0.5 border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700">
            Fit
          </button>
        </label>

        <div className="w-px h-5 bg-gray-300 dark:bg-gray-600" />

        {/* Selected cell info */}
        {selectedCell && (
          <span className="text-gray-400">
            Zelle: <span className="text-gray-600 dark:text-gray-300">{selectedCell}</span>
          </span>
        )}

        <div className="flex-1" />

        {/* Export buttons */}
        <button onClick={handleExportPdf}
          className="px-2.5 py-1 border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700">
          PDF
        </button>
        <button onClick={handleExportDocx}
          className="px-2.5 py-1 border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700">
          DOCX
        </button>
      </div>

      {/* Canvas */}
      <div className="border rounded-lg overflow-auto dark:border-gray-700 bg-gray-100 dark:bg-gray-900"
           style={{ maxHeight: '75vh' }}>
        {!ready && (
          <div className="flex items-center justify-center py-12">
            <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-teal-500" />
            <span className="ml-2 text-sm text-gray-500">Canvas wird geladen...</span>
          </div>
        )}
        <canvas ref={canvasElRef} />
      </div>

      {/* Legend */}
      <div className="flex items-center gap-4 text-xs text-gray-500">
        {Object.entries(COL_TYPE_COLORS).map(([type, color]) => (
          <span key={type} className="flex items-center gap-1">
            <span className="w-3 h-3 rounded" style={{ backgroundColor: color + '44', border: `1px solid ${color}` }} />
            {type.replace('column_', '').replace('page_', '')}
          </span>
        ))}
        <span className="ml-auto text-gray-400">Doppelklick = Text bearbeiten | Delete = Zelle entfernen | Cmd+Z = Undo</span>
      </div>
    </div>
  )
}
