'use client'

import { useEffect, useRef, useCallback, useState } from 'react'
import { useTheme } from '@/lib/ThemeContext'
import { useWorksheet } from '@/lib/worksheet-editor/WorksheetContext'
import type { EditorTool } from '@/app/worksheet-editor/types'

// Fabric.js types
declare const fabric: any

// A4 dimensions in pixels at 96 DPI
const A4_WIDTH = 794  // 210mm * 3.78
const A4_HEIGHT = 1123 // 297mm * 3.78

interface FabricCanvasProps {
  className?: string
}

export function FabricCanvas({ className = '' }: FabricCanvasProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null)
  const containerRef = useRef<HTMLDivElement>(null)
  const { isDark } = useTheme()
  const [fabricLoaded, setFabricLoaded] = useState(false)
  const [fabricCanvas, setFabricCanvas] = useState<any>(null)

  const {
    setCanvas,
    activeTool,
    setActiveTool,
    setSelectedObjects,
    zoom,
    showGrid,
    snapToGrid,
    gridSize,
    saveToHistory,
    document
  } = useWorksheet()

  // Load Fabric.js dynamically
  useEffect(() => {
    const loadFabric = async () => {
      if (typeof window !== 'undefined' && !(window as any).fabric) {
        const fabricModule = await import('fabric')
        // Fabric 6.x exports directly, not via .fabric
        ;(window as any).fabric = fabricModule
      }
      setFabricLoaded(true)
    }
    loadFabric()
  }, [])

  // Initialize canvas
  useEffect(() => {
    if (!fabricLoaded || !canvasRef.current || fabricCanvas) return

    const fabric = (window as any).fabric
    if (!fabric) return

    try {
      const canvas = new fabric.Canvas(canvasRef.current, {
        width: A4_WIDTH,
        height: A4_HEIGHT,
        backgroundColor: '#ffffff',
        selection: true,
        preserveObjectStacking: true,
        enableRetinaScaling: true,
      })

      // Store canvas reference
      setFabricCanvas(canvas)
      setCanvas(canvas)

      return () => {
        canvas.dispose()
        setFabricCanvas(null)
        setCanvas(null)
      }
    } catch (error) {
      console.error('Failed to initialize Fabric.js canvas:', error)
    }
  }, [fabricLoaded, setCanvas])

  // Save initial history entry after canvas is ready
  useEffect(() => {
    if (fabricCanvas && saveToHistory) {
      // Small delay to ensure canvas is fully initialized
      const timeout = setTimeout(() => {
        saveToHistory('initial')
      }, 100)
      return () => clearTimeout(timeout)
    }
  }, [fabricCanvas, saveToHistory])

  // Handle selection events
  useEffect(() => {
    if (!fabricCanvas) return

    const handleSelection = () => {
      const activeObjects = fabricCanvas.getActiveObjects()
      setSelectedObjects(activeObjects)
    }

    const handleSelectionCleared = () => {
      setSelectedObjects([])
    }

    fabricCanvas.on('selection:created', handleSelection)
    fabricCanvas.on('selection:updated', handleSelection)
    fabricCanvas.on('selection:cleared', handleSelectionCleared)

    return () => {
      fabricCanvas.off('selection:created', handleSelection)
      fabricCanvas.off('selection:updated', handleSelection)
      fabricCanvas.off('selection:cleared', handleSelectionCleared)
    }
  }, [fabricCanvas, setSelectedObjects])

  // Handle object modifications
  useEffect(() => {
    if (!fabricCanvas) return

    const handleModified = () => {
      saveToHistory('object:modified')
    }

    fabricCanvas.on('object:modified', handleModified)
    fabricCanvas.on('object:added', handleModified)
    fabricCanvas.on('object:removed', handleModified)

    return () => {
      fabricCanvas.off('object:modified', handleModified)
      fabricCanvas.off('object:added', handleModified)
      fabricCanvas.off('object:removed', handleModified)
    }
  }, [fabricCanvas, saveToHistory])

  // Handle zoom
  useEffect(() => {
    if (!fabricCanvas) return
    fabricCanvas.setZoom(zoom)
    fabricCanvas.setDimensions({
      width: A4_WIDTH * zoom,
      height: A4_HEIGHT * zoom
    })
    fabricCanvas.renderAll()
  }, [fabricCanvas, zoom])

  // Draw grid
  useEffect(() => {
    if (!fabricCanvas) return

    // Remove existing grid
    const existingGrid = fabricCanvas.getObjects().filter((obj: any) => obj.isGrid)
    existingGrid.forEach((obj: any) => fabricCanvas.remove(obj))

    if (showGrid) {
      const fabric = (window as any).fabric
      const gridSpacing = gridSize * 3.78 // Convert mm to pixels

      // Vertical lines
      for (let x = gridSpacing; x < A4_WIDTH; x += gridSpacing) {
        const line = new fabric.Line([x, 0, x, A4_HEIGHT], {
          stroke: isDark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)',
          strokeWidth: 0.5,
          selectable: false,
          evented: false,
          isGrid: true,
        })
        fabricCanvas.add(line)
        fabricCanvas.sendObjectToBack(line)
      }

      // Horizontal lines
      for (let y = gridSpacing; y < A4_HEIGHT; y += gridSpacing) {
        const line = new fabric.Line([0, y, A4_WIDTH, y], {
          stroke: isDark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)',
          strokeWidth: 0.5,
          selectable: false,
          evented: false,
          isGrid: true,
        })
        fabricCanvas.add(line)
        fabricCanvas.sendObjectToBack(line)
      }
    }

    fabricCanvas.renderAll()
  }, [fabricCanvas, showGrid, gridSize, isDark])

  // Handle snap to grid
  useEffect(() => {
    if (!fabricCanvas) return

    if (snapToGrid) {
      const gridSpacing = gridSize * 3.78

      fabricCanvas.on('object:moving', (e: any) => {
        const obj = e.target
        obj.set({
          left: Math.round(obj.left / gridSpacing) * gridSpacing,
          top: Math.round(obj.top / gridSpacing) * gridSpacing
        })
      })
    }
  }, [fabricCanvas, snapToGrid, gridSize])

  // Handle tool changes
  useEffect(() => {
    if (!fabricCanvas) return

    const fabric = (window as any).fabric

    // Reset drawing mode
    fabricCanvas.isDrawingMode = false
    fabricCanvas.selection = activeTool === 'select'

    // Handle canvas click based on tool
    const handleMouseDown = (e: any) => {
      if (e.target) return // Clicked on an object

      const pointer = fabricCanvas.getPointer(e.e)

      switch (activeTool) {
        case 'text': {
          const text = new fabric.IText('Text eingeben', {
            left: pointer.x,
            top: pointer.y,
            fontFamily: 'Arial',
            fontSize: 16,
            fill: isDark ? '#ffffff' : '#000000',
          })
          fabricCanvas.add(text)
          fabricCanvas.setActiveObject(text)
          text.enterEditing()
          setActiveTool('select')
          break
        }

        case 'rectangle': {
          const rect = new fabric.Rect({
            left: pointer.x,
            top: pointer.y,
            width: 100,
            height: 60,
            fill: 'transparent',
            stroke: isDark ? '#ffffff' : '#000000',
            strokeWidth: 2,
          })
          fabricCanvas.add(rect)
          fabricCanvas.setActiveObject(rect)
          setActiveTool('select')
          break
        }

        case 'circle': {
          const circle = new fabric.Circle({
            left: pointer.x,
            top: pointer.y,
            radius: 40,
            fill: 'transparent',
            stroke: isDark ? '#ffffff' : '#000000',
            strokeWidth: 2,
          })
          fabricCanvas.add(circle)
          fabricCanvas.setActiveObject(circle)
          setActiveTool('select')
          break
        }

        case 'line': {
          const line = new fabric.Line([pointer.x, pointer.y, pointer.x + 100, pointer.y], {
            stroke: isDark ? '#ffffff' : '#000000',
            strokeWidth: 2,
          })
          fabricCanvas.add(line)
          fabricCanvas.setActiveObject(line)
          setActiveTool('select')
          break
        }

        case 'arrow': {
          // Create arrow using path
          const arrowPath = `M ${pointer.x} ${pointer.y} L ${pointer.x + 80} ${pointer.y} L ${pointer.x + 70} ${pointer.y - 8} M ${pointer.x + 80} ${pointer.y} L ${pointer.x + 70} ${pointer.y + 8}`
          const arrow = new fabric.Path(arrowPath, {
            fill: 'transparent',
            stroke: isDark ? '#ffffff' : '#000000',
            strokeWidth: 2,
          })
          fabricCanvas.add(arrow)
          fabricCanvas.setActiveObject(arrow)
          setActiveTool('select')
          break
        }
      }
    }

    fabricCanvas.on('mouse:down', handleMouseDown)

    return () => {
      fabricCanvas.off('mouse:down', handleMouseDown)
    }
  }, [fabricCanvas, activeTool, isDark, setActiveTool])

  // Keyboard shortcuts
  useEffect(() => {
    if (!fabricCanvas) return

    const handleKeyDown = (e: KeyboardEvent) => {
      // Don't handle if typing in input
      if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return

      // Delete selected objects
      if (e.key === 'Delete' || e.key === 'Backspace') {
        const activeObjects = fabricCanvas.getActiveObjects()
        if (activeObjects.length > 0) {
          activeObjects.forEach((obj: any) => {
            if (!obj.isGrid) {
              fabricCanvas.remove(obj)
            }
          })
          fabricCanvas.discardActiveObject()
          fabricCanvas.renderAll()
          saveToHistory('delete')
        }
      }

      // Ctrl/Cmd shortcuts
      if (e.ctrlKey || e.metaKey) {
        switch (e.key.toLowerCase()) {
          case 'c': // Copy
            if (fabricCanvas.getActiveObject()) {
              fabricCanvas.getActiveObject().clone((cloned: any) => {
                (window as any)._clipboard = cloned
              })
            }
            break

          case 'v': // Paste
            if ((window as any)._clipboard) {
              (window as any)._clipboard.clone((cloned: any) => {
                cloned.set({
                  left: cloned.left + 20,
                  top: cloned.top + 20,
                })
                fabricCanvas.add(cloned)
                fabricCanvas.setActiveObject(cloned)
                fabricCanvas.renderAll()
                saveToHistory('paste')
              })
            }
            break

          case 'a': // Select all
            e.preventDefault()
            const objects = fabricCanvas.getObjects().filter((obj: any) => !obj.isGrid)
            const fabric = (window as any).fabric
            const selection = new fabric.ActiveSelection(objects, { canvas: fabricCanvas })
            fabricCanvas.setActiveObject(selection)
            fabricCanvas.renderAll()
            break

          case 'd': // Duplicate
            e.preventDefault()
            if (fabricCanvas.getActiveObject()) {
              fabricCanvas.getActiveObject().clone((cloned: any) => {
                cloned.set({
                  left: cloned.left + 20,
                  top: cloned.top + 20,
                })
                fabricCanvas.add(cloned)
                fabricCanvas.setActiveObject(cloned)
                fabricCanvas.renderAll()
                saveToHistory('duplicate')
              })
            }
            break
        }
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [fabricCanvas, saveToHistory])

  // Add image to canvas
  const addImage = useCallback((url: string) => {
    if (!fabricCanvas) return

    const fabric = (window as any).fabric
    fabric.Image.fromURL(url, (img: any) => {
      // Scale image to fit within canvas
      const maxWidth = A4_WIDTH * 0.8
      const maxHeight = A4_HEIGHT * 0.5
      const scale = Math.min(maxWidth / img.width, maxHeight / img.height, 1)

      img.set({
        left: (A4_WIDTH - img.width * scale) / 2,
        top: (A4_HEIGHT - img.height * scale) / 2,
        scaleX: scale,
        scaleY: scale,
      })

      fabricCanvas.add(img)
      fabricCanvas.setActiveObject(img)
      fabricCanvas.renderAll()
      saveToHistory('image:added')
      setActiveTool('select')
    }, { crossOrigin: 'anonymous' })
  }, [fabricCanvas, saveToHistory, setActiveTool])

  // Expose addImage to context
  useEffect(() => {
    if (fabricCanvas) {
      (fabricCanvas as any).addImage = addImage
    }
  }, [fabricCanvas, addImage])

  // Background styling
  const canvasContainerStyle = isDark
    ? 'bg-slate-800 shadow-2xl'
    : 'bg-slate-200 shadow-xl'

  return (
    <div
      ref={containerRef}
      className={`flex items-center justify-center overflow-auto p-8 ${className}`}
      style={{ minHeight: '100%' }}
    >
      <div className={`rounded-lg overflow-hidden ${canvasContainerStyle}`}>
        <canvas ref={canvasRef} id="worksheet-canvas" />
      </div>
    </div>
  )
}
