'use client'

import React, { createContext, useContext, useState, useCallback, useRef, useEffect, ReactNode } from 'react'
import type { Canvas, Object as FabricObject } from 'fabric'
import type {
  EditorTool,
  WorksheetDocument,
  WorksheetPage,
  PageFormat,
  HistoryEntry,
  DEFAULT_PAGE_FORMAT
} from '@/app/worksheet-editor/types'

// Context Types
interface WorksheetContextType {
  // Canvas
  canvas: Canvas | null
  setCanvas: (canvas: Canvas | null) => void

  // Document
  document: WorksheetDocument | null
  setDocument: (doc: WorksheetDocument | null) => void

  // Tool State
  activeTool: EditorTool
  setActiveTool: (tool: EditorTool) => void

  // Selection
  selectedObjects: FabricObject[]
  setSelectedObjects: (objects: FabricObject[]) => void

  // Zoom
  zoom: number
  setZoom: (zoom: number) => void
  zoomIn: () => void
  zoomOut: () => void
  zoomToFit: () => void

  // Grid
  showGrid: boolean
  setShowGrid: (show: boolean) => void
  snapToGrid: boolean
  setSnapToGrid: (snap: boolean) => void
  gridSize: number
  setGridSize: (size: number) => void

  // Pages
  currentPageIndex: number
  setCurrentPageIndex: (index: number) => void
  addPage: () => void
  deletePage: (index: number) => void

  // History
  canUndo: boolean
  canRedo: boolean
  undo: () => void
  redo: () => void
  saveToHistory: (action: string) => void

  // Save/Load
  saveDocument: () => Promise<void>
  loadDocument: (id: string) => Promise<void>

  // Export
  exportToPDF: () => Promise<Blob>
  exportToImage: (format: 'png' | 'jpg') => Promise<Blob>

  // Dirty State
  isDirty: boolean
  setIsDirty: (dirty: boolean) => void
}

const WorksheetContext = createContext<WorksheetContextType | null>(null)

// Provider Props
interface WorksheetProviderProps {
  children: ReactNode
}

// Generate unique ID
const generateId = () => `ws_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`

// Default Page Format
const defaultPageFormat: PageFormat = {
  width: 210,
  height: 297,
  orientation: 'portrait',
  margins: { top: 15, right: 15, bottom: 15, left: 15 }
}

export function WorksheetProvider({ children }: WorksheetProviderProps) {
  // Canvas State
  const [canvas, setCanvas] = useState<Canvas | null>(null)

  // Document State
  const [document, setDocument] = useState<WorksheetDocument | null>(null)

  // Editor State
  const [activeTool, setActiveTool] = useState<EditorTool>('select')
  const [selectedObjects, setSelectedObjects] = useState<FabricObject[]>([])
  const [zoom, setZoom] = useState(1)
  const [showGrid, setShowGrid] = useState(true)
  const [snapToGrid, setSnapToGrid] = useState(true)
  const [gridSize, setGridSize] = useState(10)
  const [currentPageIndex, setCurrentPageIndex] = useState(0)
  const [isDirty, setIsDirty] = useState(false)

  // History State
  const historyRef = useRef<HistoryEntry[]>([])
  const historyIndexRef = useRef(-1)
  const [canUndo, setCanUndo] = useState(false)
  const [canRedo, setCanRedo] = useState(false)

  // Initialize empty document
  useEffect(() => {
    if (!document) {
      const newDoc: WorksheetDocument = {
        id: generateId(),
        title: 'Neues Arbeitsblatt',
        pages: [{
          id: generateId(),
          index: 0,
          canvasJSON: ''
        }],
        pageFormat: defaultPageFormat,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      }
      setDocument(newDoc)
    }
  }, [document])

  // Zoom functions
  const zoomIn = useCallback(() => {
    setZoom(prev => Math.min(prev * 1.2, 4))
  }, [])

  const zoomOut = useCallback(() => {
    setZoom(prev => Math.max(prev / 1.2, 0.25))
  }, [])

  const zoomToFit = useCallback(() => {
    setZoom(1)
  }, [])

  // Page functions
  const addPage = useCallback(() => {
    if (!document) return

    const newPage: WorksheetPage = {
      id: generateId(),
      index: document.pages.length,
      canvasJSON: ''
    }

    setDocument({
      ...document,
      pages: [...document.pages, newPage],
      updatedAt: new Date().toISOString()
    })
    setCurrentPageIndex(document.pages.length)
    setIsDirty(true)
  }, [document])

  const deletePage = useCallback((index: number) => {
    if (!document || document.pages.length <= 1) return

    const newPages = document.pages.filter((_, i) => i !== index)
      .map((page, i) => ({ ...page, index: i }))

    setDocument({
      ...document,
      pages: newPages,
      updatedAt: new Date().toISOString()
    })

    if (currentPageIndex >= newPages.length) {
      setCurrentPageIndex(newPages.length - 1)
    }
    setIsDirty(true)
  }, [document, currentPageIndex])

  // History functions
  const saveToHistory = useCallback((action: string) => {
    if (!canvas) return

    try {
      const canvasData = canvas.toJSON()
      if (!canvasData) return

      const entry: HistoryEntry = {
        canvasJSON: JSON.stringify(canvasData),
        timestamp: Date.now(),
        action
      }

      // Remove any future history if we're not at the end
      if (historyIndexRef.current < historyRef.current.length - 1) {
        historyRef.current = historyRef.current.slice(0, historyIndexRef.current + 1)
      }

      historyRef.current.push(entry)
      historyIndexRef.current = historyRef.current.length - 1

      // Limit history size
      if (historyRef.current.length > 50) {
        historyRef.current.shift()
        historyIndexRef.current--
      }

      setCanUndo(historyIndexRef.current > 0)
      setCanRedo(false)
      setIsDirty(true)
    } catch (error) {
      console.error('Failed to save history:', error)
    }
  }, [canvas])

  const undo = useCallback(() => {
    if (!canvas || historyIndexRef.current <= 0) return

    historyIndexRef.current--
    const entry = historyRef.current[historyIndexRef.current]

    canvas.loadFromJSON(JSON.parse(entry.canvasJSON), () => {
      canvas.renderAll()
    })

    setCanUndo(historyIndexRef.current > 0)
    setCanRedo(true)
  }, [canvas])

  const redo = useCallback(() => {
    if (!canvas || historyIndexRef.current >= historyRef.current.length - 1) return

    historyIndexRef.current++
    const entry = historyRef.current[historyIndexRef.current]

    canvas.loadFromJSON(JSON.parse(entry.canvasJSON), () => {
      canvas.renderAll()
    })

    setCanUndo(true)
    setCanRedo(historyIndexRef.current < historyRef.current.length - 1)
  }, [canvas])

  // Save/Load functions
  const saveDocument = useCallback(async () => {
    if (!canvas || !document) return

    // Save current page state
    const currentPage = document.pages[currentPageIndex]
    currentPage.canvasJSON = JSON.stringify(canvas.toJSON())

    // Get API base URL (use same protocol as page)
    const { hostname, protocol } = window.location
    const apiBase = hostname === 'localhost' ? 'http://localhost:8086' : `${protocol}//${hostname}:8086`

    try {
      const response = await fetch(`${apiBase}/api/v1/worksheet/save`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(document)
      })

      if (!response.ok) throw new Error('Failed to save')

      const result = await response.json()
      setDocument({ ...document, id: result.id })
      setIsDirty(false)
    } catch (error) {
      console.error('Save failed:', error)
      // Fallback to localStorage
      localStorage.setItem(`worksheet_${document.id}`, JSON.stringify(document))
      setIsDirty(false)
    }
  }, [canvas, document, currentPageIndex])

  const loadDocument = useCallback(async (id: string) => {
    const { hostname, protocol } = window.location
    const apiBase = hostname === 'localhost' ? 'http://localhost:8086' : `${protocol}//${hostname}:8086`

    try {
      const response = await fetch(`${apiBase}/api/v1/worksheet/${id}`)

      if (!response.ok) throw new Error('Failed to load')

      const doc = await response.json()
      setDocument(doc)
      setCurrentPageIndex(0)

      if (canvas && doc.pages[0]?.canvasJSON) {
        canvas.loadFromJSON(JSON.parse(doc.pages[0].canvasJSON), () => {
          canvas.renderAll()
        })
      }
    } catch (error) {
      console.error('Load failed:', error)
      // Try localStorage fallback
      const stored = localStorage.getItem(`worksheet_${id}`)
      if (stored) {
        const doc = JSON.parse(stored)
        setDocument(doc)
        setCurrentPageIndex(0)
      }
    }
  }, [canvas])

  // Export functions
  const exportToPDF = useCallback(async (): Promise<Blob> => {
    if (!canvas || !document) throw new Error('No canvas or document')

    const { PDFDocument, rgb } = await import('pdf-lib')

    const pdfDoc = await PDFDocument.create()

    for (const page of document.pages) {
      const pdfPage = pdfDoc.addPage([
        document.pageFormat.width * 2.83465, // mm to points
        document.pageFormat.height * 2.83465
      ])

      // Export canvas as PNG and embed
      if (page.canvasJSON) {
        // Load the page content
        if (currentPageIndex !== page.index) {
          await new Promise<void>((resolve) => {
            canvas.loadFromJSON(JSON.parse(page.canvasJSON), () => {
              canvas.renderAll()
              resolve()
            })
          })
        }

        const dataUrl = canvas.toDataURL({ format: 'png', multiplier: 2 })
        const imageBytes = await fetch(dataUrl).then(res => res.arrayBuffer())
        const image = await pdfDoc.embedPng(imageBytes)

        pdfPage.drawImage(image, {
          x: 0,
          y: 0,
          width: pdfPage.getWidth(),
          height: pdfPage.getHeight()
        })
      }
    }

    const pdfBytes = await pdfDoc.save()
    // Convert Uint8Array to ArrayBuffer for Blob compatibility
    const arrayBuffer = pdfBytes.slice().buffer as ArrayBuffer
    return new Blob([arrayBuffer], { type: 'application/pdf' })
  }, [canvas, document, currentPageIndex])

  const exportToImage = useCallback(async (format: 'png' | 'jpg'): Promise<Blob> => {
    if (!canvas) throw new Error('No canvas')

    // Fabric.js uses 'jpeg' not 'jpg'
    const fabricFormat = format === 'jpg' ? 'jpeg' : format
    const dataUrl = canvas.toDataURL({
      format: fabricFormat as 'png' | 'jpeg',
      quality: format === 'jpg' ? 0.9 : undefined,
      multiplier: 2
    })

    const response = await fetch(dataUrl)
    return response.blob()
  }, [canvas])

  const value: WorksheetContextType = {
    canvas,
    setCanvas,
    document,
    setDocument,
    activeTool,
    setActiveTool,
    selectedObjects,
    setSelectedObjects,
    zoom,
    setZoom,
    zoomIn,
    zoomOut,
    zoomToFit,
    showGrid,
    setShowGrid,
    snapToGrid,
    setSnapToGrid,
    gridSize,
    setGridSize,
    currentPageIndex,
    setCurrentPageIndex,
    addPage,
    deletePage,
    canUndo,
    canRedo,
    undo,
    redo,
    saveToHistory,
    saveDocument,
    loadDocument,
    exportToPDF,
    exportToImage,
    isDirty,
    setIsDirty
  }

  return (
    <WorksheetContext.Provider value={value}>
      {children}
    </WorksheetContext.Provider>
  )
}

export function useWorksheet() {
  const context = useContext(WorksheetContext)
  if (!context) {
    throw new Error('useWorksheet must be used within a WorksheetProvider')
  }
  return context
}
