'use client'

import { useState, useRef, useCallback, useEffect } from 'react'
import { useRouter } from 'next/navigation'
import { DndProvider } from 'react-dnd'
import { MultiBackend, TouchTransition, MouseTransition } from 'react-dnd-multi-backend'
import { HTML5Backend } from 'react-dnd-html5-backend'
import { TouchBackend } from 'react-dnd-touch-backend'
import { MapView } from '@/components/map/map-view'
import { Topbar } from '@/components/layout/topbar'
import { LeftToolbar } from '@/components/layout/left-toolbar'
import { RightSidebar } from '@/components/layout/right-sidebar'
import { ProjectDialog } from '@/components/dialogs/project-dialog'
import { ExerciseCockpit } from '@/components/exercise/exercise-cockpit'
import { TextDialog } from '@/components/dialogs/text-dialog'
import { LineLabelDialog } from '@/components/dialogs/line-label-dialog'
import { useToast } from '@/components/ui/use-toast'
import { useAuth } from '@/components/providers/auth-provider'
import { Button } from '@/components/ui/button'
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'
import { JournalView } from '@/components/journal/journal-view'
import { Lock, Unlock, Eye, AlertTriangle, WifiOff, GraduationCap, Map as MapIcon, ClipboardList, LayoutGrid, X } from 'lucide-react'
import { CustomDragLayer } from '@/components/map/custom-drag-layer'
import { OnboardingTour, resetOnboardingTour } from '@/components/onboarding/onboarding-tour'
import { useKeyboardShortcuts } from '@/hooks/use-keyboard-shortcuts'
import { useMapExport } from '@/hooks/use-map-export'
import { useAutoSave } from '@/hooks/use-auto-save'
import { useOfflineSync } from '@/hooks/use-offline-sync'
import { useRealtimeSync } from '@/hooks/use-realtime-sync'
import type { Project, ProjectMode, DrawFeature, Feature, JournalEntry, DrawMode } from '@/types'
import { useToolStore } from '@/stores/tool-store'
import { useUIStore } from '@/stores/ui-store'

export type { DrawMode }

export default function AppPage() {
  const router = useRouter()
  const { toast } = useToast()
  const { user, tenant, loading: authLoading, logout } = useAuth()

  // Zustand Stores
  const { activeTool: drawMode, setActiveTool: setDrawMode, activeColor: selectedColor, setActiveColor: setSelectedColor, lineWidth: selectedWidth, setLineWidth: setSelectedWidth } = useToolStore()
  const { sidebarOpen: isSidebarOpen, setSidebarOpen: setIsSidebarOpen, sidebarTab: activeTab, setSidebarTab: setActiveTab } = useUIStore()

  const [currentProject, setCurrentProject] = useState<Project | null>(null)
  const [features, setFeatures] = useState<DrawFeature[]>([])
  
  const [isProjectDialogOpen, setIsProjectDialogOpen] = useState(false)
  const [newProjectMode, setNewProjectMode] = useState<ProjectMode>('EINSATZ')
  const [isEndConfirmOpen, setIsEndConfirmOpen] = useState(false)
  // Tap-to-place: angetipptes Symbol wartet auf Platzierung per Karten-Tipp (Mobil)
  const [pendingSymbol, setPendingSymbol] = useState<{ id: string; imageUrl: string } | null>(null)
  const [isSaving, setIsSaving] = useState(false)
  const [isDeleteAllConfirmOpen, setIsDeleteAllConfirmOpen] = useState(false)
  const [isFullscreen, setIsFullscreen] = useState(false)
  const [auditLog, setAuditLog] = useState<{ time: string; action: string }[]>([])
  const [isAuditOpen, setIsAuditOpen] = useState(false)
  const [presentationLocked, setPresentationLocked] = useState(false)

  const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false)
  const [lastMapScreenshot, setLastMapScreenshot] = useState<string>('')
  const [defaultSymbolScale, setDefaultSymbolScale] = useState(1.5)

  // Onboarding tour
  const [showTour, setShowTour] = useState(false)

  // Ref to access the map for export
  const mapRef = useRef<any>(null)

  // Undo/Redo history
  const undoStackRef = useRef<DrawFeature[][]>([])
  const redoStackRef = useRef<DrawFeature[][]>([])

  // Ref to always have latest features (avoids stale closures in callbacks called via refs)
  const featuresRef = useRef<DrawFeature[]>(features)
  useEffect(() => { featuresRef.current = features }, [features])

  // Optimistischer Lock: Features-Version des aktuellen Projekts mitführen
  const featuresVersionRef = useRef<number>(0)

  // Ref for undo-draw-point (removes last point during line drawing)
  const undoDrawPointRef = useRef<(() => boolean) | null>(null)

  // Realtime sync: editing lock, socket.io, throttled broadcast
  const {
    editingBy, isEditingByMe, editingLoading,
    socketRef, broadcastFeatures,
    handleStartEditing, handleStopEditing,
  } = useRealtimeSync({
    currentProject,
    user: user ? { id: user.id, name: user.name, role: user.role } : null,
    featuresRef,
    setFeatures,
    toast: toast as any,
  })

  // Capture map screenshot when switching to journal tab (coordinate-based rendering)
  const handleTabChange = useCallback(async (tab: 'map' | 'journal') => {
    if (tab === 'journal' && mapRef.current) {
      try {
        const mapInstance = mapRef.current
        const mapCanvas = mapInstance.getCanvas() as HTMLCanvasElement
        if (mapCanvas && mapCanvas.width > 0) {
          const offscreen = document.createElement('canvas')
          offscreen.width = mapCanvas.width
          offscreen.height = mapCanvas.height
          const ctx = offscreen.getContext('2d')
          if (ctx) {
            ctx.drawImage(mapCanvas, 0, 0)

            const container = mapInstance.getContainer()
            const dpr = mapCanvas.width / container.offsetWidth
            const currentZoom = mapInstance.getZoom()
            const currentFeatures = featuresRef.current

            // Helper: haversine distance
            const haversine = (a: number[], b: number[]): number => {
              const R = 6371000, toRad = Math.PI / 180
              const dLat = (b[1] - a[1]) * toRad, dLng = (b[0] - a[0]) * toRad
              const x = Math.sin(dLat / 2) ** 2 + Math.cos(a[1] * toRad) * Math.cos(b[1] * toRad) * Math.sin(dLng / 2) ** 2
              return R * 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x))
            }

            // Helper: load image as promise
            const loadImage = (src: string): Promise<HTMLImageElement> => new Promise((resolve, reject) => {
              const img = new Image()
              img.crossOrigin = 'anonymous'
              img.onload = () => resolve(img)
              img.onerror = reject
              img.src = src
            })

            // 1. Draw symbol features (coordinate-based)
            for (const f of currentFeatures.filter(f => f.type === 'symbol')) {
              if (f.geometry.type !== 'Point') continue
              const coords = f.geometry.coordinates as [number, number]
              const pixel = mapInstance.project(coords)
              const px = pixel.x * dpr
              const py = pixel.y * dpr
              const scale = (f.properties.scale as number) || 1
              const rotation = (f.properties.rotation as number) || 0
              const baseSize = 32
              const placementZoom = (f.properties.placementZoom as number) || 17
              const zoomFactor = Math.pow(2, currentZoom - placementZoom)
              const size = Math.max(8, Math.min(400, baseSize * scale * zoomFactor)) * dpr

              const iconId = f.properties.iconId as string
              const imageUrl = f.properties.imageUrl as string
              let imgSrc = imageUrl || ''
              if (!imgSrc && iconId) {
                const { getSymbolById, getSymbolDataUri } = await import('@/lib/fw-symbols')
                const sym = getSymbolById(iconId)
                if (sym) imgSrc = getSymbolDataUri(sym)
              }
              if (imgSrc) {
                try {
                  const img = await loadImage(imgSrc)
                  const imgAspect = img.naturalWidth / img.naturalHeight
                  let drawW = size, drawH = size
                  if (imgAspect > 1) drawH = size / imgAspect
                  else drawW = size * imgAspect
                  ctx.save()
                  ctx.translate(px, py)
                  ctx.rotate((rotation * Math.PI) / 180)
                  ctx.drawImage(img, -drawW / 2, -drawH / 2, drawW, drawH)
                  ctx.restore()
                } catch {}
              }
            }

            // 2. Draw arrowheads for arrow features
            for (const f of currentFeatures.filter(f => f.type === 'arrow')) {
              if (f.geometry.type !== 'LineString') continue
              const lineCoords = f.geometry.coordinates as number[][]
              if (lineCoords.length < 2) continue
              const p1 = lineCoords[lineCoords.length - 2]
              const p2 = lineCoords[lineCoords.length - 1]
              const px1 = mapInstance.project(p1 as [number, number])
              const px2 = mapInstance.project(p2 as [number, number])
              const angle = Math.atan2(px2.y - px1.y, px2.x - px1.x)
              const color = (f.properties.color as string) || '#000000'
              const arrowSize = 14 * dpr

              ctx.save()
              ctx.translate(px2.x * dpr, px2.y * dpr)
              ctx.rotate(angle + Math.PI / 2)
              ctx.beginPath()
              ctx.moveTo(0, -arrowSize)
              ctx.lineTo(-arrowSize * 0.7, arrowSize * 0.3)
              ctx.lineTo(arrowSize * 0.7, arrowSize * 0.3)
              ctx.closePath()
              ctx.fillStyle = color
              ctx.fill()
              ctx.restore()
            }

            // 3. Draw line/polygon labels at midpoints
            for (const f of currentFeatures.filter(f => f.properties.label && (f.geometry.type === 'LineString' || f.geometry.type === 'Polygon'))) {
              const label = f.properties.label as string
              let midpoint: [number, number]

              if (f.geometry.type === 'LineString') {
                const coords = f.geometry.coordinates as number[][]
                const midIdx = Math.floor(coords.length / 2)
                if (coords.length === 2) {
                  midpoint = [(coords[0][0] + coords[1][0]) / 2, (coords[0][1] + coords[1][1]) / 2]
                } else {
                  midpoint = coords[midIdx] as [number, number]
                }
              } else {
                const ring = (f.geometry.coordinates as number[][][])[0]
                const len = ring.length - 1
                let cx = 0, cy = 0
                for (let i = 0; i < len; i++) { cx += ring[i][0]; cy += ring[i][1] }
                midpoint = [cx / len, cy / len]
              }

              const pixel = mapInstance.project(midpoint)
              const px = pixel.x * dpr
              const py = pixel.y * dpr
              const isDanger = f.type === 'dangerzone'
              const bgColor = isDanger ? 'rgba(220,38,38,0.85)' : 'rgba(0,0,0,0.75)'
              const borderColor = isDanger ? '#dc2626' : 'rgba(255,255,255,0.5)'

              // Build label text with line info
              let displayText = label
              let infoText = ''
              if (f.geometry.type === 'LineString') {
                const lineCoords = f.geometry.coordinates as number[][]
                let totalLen = 0
                for (let i = 1; i < lineCoords.length; i++) {
                  totalLen += haversine(lineCoords[i - 1], lineCoords[i])
                }
                const hoseCount = Math.ceil(totalLen / 20)
                const lenText = totalLen < 1000 ? `${Math.round(totalLen)}m` : `${(totalLen / 1000).toFixed(2)}km`
                infoText = `${lenText} / ${hoseCount} Schl.`
              }

              const fontSize1 = 11 * dpr
              const fontSize2 = 8 * dpr
              const padX = 6 * dpr
              const padY = 3 * dpr

              ctx.save()
              ctx.font = `bold ${fontSize1}px system-ui, sans-serif`
              const w1 = ctx.measureText(displayText).width
              let w2 = 0
              if (infoText) {
                ctx.font = `${fontSize2}px system-ui, sans-serif`
                w2 = ctx.measureText(infoText).width
              }
              const boxW = Math.max(w1, w2) + padX * 2
              const boxH = fontSize1 + (infoText ? fontSize2 + 2 * dpr : 0) + padY * 2
              const radius = 3 * dpr

              // Background
              ctx.fillStyle = bgColor
              ctx.beginPath()
              ctx.roundRect(px - boxW / 2, py - boxH / 2, boxW, boxH, radius)
              ctx.fill()
              // Border
              ctx.strokeStyle = borderColor
              ctx.lineWidth = 1 * dpr
              ctx.beginPath()
              ctx.roundRect(px - boxW / 2, py - boxH / 2, boxW, boxH, radius)
              ctx.stroke()
              // Label text
              ctx.fillStyle = '#ffffff'
              ctx.font = `bold ${fontSize1}px system-ui, sans-serif`
              ctx.textAlign = 'center'
              ctx.textBaseline = 'middle'
              const textY = infoText ? py - fontSize2 / 2 : py
              ctx.fillText(displayText, px, textY)
              // Info text
              if (infoText) {
                ctx.font = `${fontSize2}px system-ui, sans-serif`
                ctx.globalAlpha = 0.8
                ctx.fillText(infoText, px, py + fontSize1 / 2 + 1 * dpr)
                ctx.globalAlpha = 1
              }
              ctx.restore()
            }

            // 4. Draw text features
            for (const f of currentFeatures.filter(f => f.type === 'text')) {
              if (f.geometry.type !== 'Point') continue
              const coords = f.geometry.coordinates as [number, number]
              const pixel = mapInstance.project(coords)
              const px = pixel.x * dpr
              const py = pixel.y * dpr
              const text = (f.properties.text as string) || ''
              const fontSize = ((f.properties.fontSize as number) || 14) * dpr
              const color = (f.properties.color as string) || '#000000'

              ctx.save()
              ctx.font = `bold ${fontSize}px system-ui, sans-serif`
              ctx.textAlign = 'center'
              ctx.textBaseline = 'middle'
              ctx.strokeStyle = '#ffffff'
              ctx.lineWidth = 3 * dpr
              ctx.lineJoin = 'round'
              ctx.strokeText(text, px, py)
              ctx.fillStyle = color
              ctx.fillText(text, px, py)
              ctx.restore()
            }

            setLastMapScreenshot(offscreen.toDataURL('image/png'))
          } else {
            setLastMapScreenshot(mapCanvas.toDataURL('image/png'))
          }
        }
      } catch (e) { console.warn('Map screenshot on tab switch failed:', e) }
    }
    setActiveTab(tab)
  }, [])

  useEffect(() => {
    if (activeTab === 'map' && mapRef.current) {
      setTimeout(() => mapRef.current?.resize(), 50)
    }
  }, [activeTab, isSidebarCollapsed])

  // Theme: Tag/Nacht mode
  const [isDarkMode, setIsDarkMode] = useState(false)

  useEffect(() => {
    // Restore theme from localStorage
    const saved = localStorage.getItem('lageplan-theme')
    if (saved === 'dark') {
      setIsDarkMode(true)
      document.documentElement.classList.add('dark')
    }
  }, [])

  const toggleTheme = useCallback(() => {
    setIsDarkMode(prev => {
      const next = !prev
      if (next) {
        document.documentElement.classList.add('dark')
        localStorage.setItem('lageplan-theme', 'dark')
      } else {
        document.documentElement.classList.remove('dark')
        localStorage.setItem('lageplan-theme', 'light')
      }
      return next
    })
  }, [])

  // Text dialog state
  const [isTextDialogOpen, setIsTextDialogOpen] = useState(false)
  const [textPlaceCoords, setTextPlaceCoords] = useState<[number, number] | null>(null)

  // Line label dialog state
  const [isLineLabelDialogOpen, setIsLineLabelDialogOpen] = useState(false)
  const [pendingLineFeature, setPendingLineFeature] = useState<DrawFeature | null>(null)

  // Offline detection + sync queue management
  const { isOffline, syncQueueCount, setSyncQueueCount } = useOfflineSync({ toast: toast as any })

  // Audit trail helper
  const addAudit = useCallback((action: string) => {
    const time = new Date().toLocaleTimeString('de-CH', { hour: '2-digit', minute: '2-digit', second: '2-digit' })
    setAuditLog(prev => [{ time, action }, ...prev].slice(0, 100))
  }, [])

  // Register service worker for offline tile caching
  useEffect(() => {
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/sw.js').catch(() => {})
    }
    // Load default symbol scale from server settings
    fetch('/api/settings/public').then(r => r.json()).then(d => {
      if (d.defaultSymbolScale) setDefaultSymbolScale(d.defaultSymbolScale)
    }).catch(() => {})
  }, [])

  // Redirect to login if not authenticated
  useEffect(() => {
    if (!authLoading && !user) {
      router.push('/login')
    }
  }, [authLoading, user, router])

  const roleCanEdit = user ? (user.role === 'SERVER_ADMIN' || user.role === 'TENANT_ADMIN' || user.role === 'OPERATOR') : false
  // Karte: nur mit Editing-Lock bearbeitbar (verhindert Zeichen-Konflikte).
  // Journal/Cockpit: unabhängig vom Karten-Lock — so kann eine Person zeichnen,
  // während eine andere parallel das Journal führt (Führungsstab-Szenario).
  const canEditMap = !presentationLocked && roleCanEdit && (isEditingByMe || !editingBy)
  const canEditJournal = !presentationLocked && roleCanEdit
  const canEdit = canEditMap // Abwärtskompatibel für Karten-bezogene Stellen
  const isReadOnly = !!editingBy && !isEditingByMe

  // Features-Version bei Projektwechsel initialisieren
  useEffect(() => {
    featuresVersionRef.current = (currentProject as any)?.featuresVersion ?? 0
  }, [currentProject?.id])

  // Speicher-Konflikt: Server-Stand übernehmen und den Nutzer warnen
  const handleSaveConflict = useCallback((serverFeatures: DrawFeature[], serverVersion: number) => {
    setFeatures(serverFeatures)
    featuresVersionRef.current = serverVersion
    undoStackRef.current = []
    redoStackRef.current = []
    toast({
      title: 'Konflikt erkannt',
      description: 'Der Einsatz wurde von jemand anderem geändert — der aktuelle Stand wurde geladen. Bitte prüfe deine Änderungen und mache sie ggf. erneut.',
      variant: 'destructive',
    })
  }, [toast])

  // Auto-save: localStorage persistence + debounced API save + beacon on unload
  useAutoSave({
    currentProject,
    features,
    featuresRef,
    mapRef,
    socketRef,
    isEditingByMe,
    setSyncQueueCount,
    featuresVersionRef,
    onConflict: handleSaveConflict,
  })

  // Fullscreen toggle
  const toggleFullscreen = useCallback(() => {
    if (!document.fullscreenElement) {
      document.documentElement.requestFullscreen().catch(() => {})
      setIsFullscreen(true)
    } else {
      document.exitFullscreen().catch(() => {})
      setIsFullscreen(false)
    }
  }, [])

  useEffect(() => {
    const handler = () => setIsFullscreen(!!document.fullscreenElement)
    document.addEventListener('fullscreenchange', handler)
    return () => document.removeEventListener('fullscreenchange', handler)
  }, [])

  // Persist current project to localStorage
  useEffect(() => {
    if (currentProject) {
      localStorage.setItem('lageplan-project', JSON.stringify(currentProject))
    }
  }, [currentProject])

  // Restore from localStorage on mount — validate project belongs to current user
  useEffect(() => {
    if (authLoading || !user) return
    try {
      const savedProject = localStorage.getItem('lageplan-project')
      if (savedProject) {
        const proj = JSON.parse(savedProject)
        // Verify the project is accessible by the current user
        fetch(`/api/projects/${proj.id}`).then(res => {
          if (res.ok) {
            res.json().then(data => {
              setCurrentProject(data.project)
              // Also restore features from the API (authoritative)
              const apiFeatures = data.project.features || []
              if (apiFeatures.length > 0) {
                setFeatures(apiFeatures)
              } else {
                const savedFeatures = localStorage.getItem(`lageplan-features-${proj.id}`)
                if (savedFeatures) setFeatures(JSON.parse(savedFeatures))
              }
            })
          } else {
            // Project not accessible (different tenant, deleted, etc.) — clear
            console.log('[Restore] Project not accessible for current user, clearing')
            localStorage.removeItem('lageplan-project')
            localStorage.removeItem(`lageplan-features-${proj.id}`)
            setCurrentProject(null)
            setFeatures([])
          }
        }).catch(() => {
          // Network error — use cached data as fallback (nur Features DESSELBEN Projekts)
          setCurrentProject(proj)
          const savedFeatures = localStorage.getItem(`lageplan-features-${proj.id}`)
          if (savedFeatures) setFeatures(JSON.parse(savedFeatures))
        })
      }
    } catch (e) {
      console.error('Error restoring from localStorage:', e)
    }
  }, [authLoading, user])

  const handleNewProject = (mode: ProjectMode = 'EINSATZ') => {
    setNewProjectMode(mode)
    setIsProjectDialogOpen(true)
  }

  const handleProjectCreated = (project: Project) => {
    // If the project has geocoded coordinates from address search, use those
    // Otherwise preserve current map position
    const hasGeocodedCenter = project.mapCenter &&
      project.mapCenter.lng !== 8.5417 && project.mapCenter.lat !== 47.3769 // not the API default
    if (!hasGeocodedCenter && mapRef.current) {
      const center = mapRef.current.getCenter()
      const zoom = mapRef.current.getZoom()
      project.mapCenter = { lng: center.lng, lat: center.lat }
      project.mapZoom = zoom
    }
    setCurrentProject(project)
    setFeatures([])
    undoStackRef.current = []
    redoStackRef.current = []
    setIsProjectDialogOpen(false)
    addAudit(`Einsatz "${project.title}" erstellt`)
    toast({
      title: 'Einsatz erstellt',
      description: `"${project.title}" wurde erfolgreich erstellt.`,
    })
  }

  const handleProjectLoaded = (project: Project, loadedFeatures: DrawFeature[]) => {
    setCurrentProject(project)
    setFeatures(loadedFeatures)
    undoStackRef.current = []
    redoStackRef.current = []
    addAudit(`Einsatz "${project.title}" geladen (${loadedFeatures.length} Elemente)`)
    toast({
      title: 'Einsatz geladen',
      description: `"${project.title}" wurde geladen.`,
    })
  }

  const handleDeleteProject = (deletedId: string) => {
    if (currentProject?.id === deletedId) {
      setCurrentProject(null)
      setFeatures([])
      undoStackRef.current = []
      redoStackRef.current = []
      localStorage.removeItem('lageplan-project')
      localStorage.removeItem(`lageplan-features-${deletedId}`)
    }
    addAudit(`Einsatz gelöscht`)
    toast({
      title: 'Einsatz gelöscht',
      description: 'Der Einsatz wurde endgültig gelöscht.',
    })
  }

  const handleSaveProject = async () => {
    if (!currentProject) return

    setIsSaving(true)
    try {
      const saveBody: any = { features, baseVersion: featuresVersionRef.current }
      if (mapRef.current) {
        const c = mapRef.current.getCenter()
        saveBody.mapCenter = { lng: c.lng, lat: c.lat }
        saveBody.mapZoom = mapRef.current.getZoom()
      }
      let res = await fetch(`/api/projects/${currentProject.id}/features`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(saveBody),
      })

      // If project doesn't exist in DB (404), re-create it first then retry
      if (res.status === 404) {
        const createRes = await fetch('/api/projects', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            title: currentProject.title,
            mode: currentProject.mode,
            location: currentProject.location || undefined,
            description: currentProject.description || undefined,
            einsatzleiter: currentProject.einsatzleiter || undefined,
            journalfuehrer: currentProject.journalfuehrer || undefined,
          }),
        })
        if (!createRes.ok) {
          const err = await createRes.json().catch(() => ({}))
          throw new Error(err.error || 'Projekt konnte nicht erstellt werden')
        }
        const created = await createRes.json()
        setCurrentProject(created.project)
        featuresVersionRef.current = created.project?.featuresVersion ?? 0
        // Retry save with new project ID
        res = await fetch(`/api/projects/${created.project.id}/features`, {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ features, baseVersion: featuresVersionRef.current }),
        })
      }

      // Versionskonflikt: Server-Stand übernehmen statt zu überschreiben
      if (res.status === 409) {
        const data = await res.json().catch(() => null)
        if (data?.conflict) {
          handleSaveConflict(data.features || [], data.featuresVersion ?? featuresVersionRef.current)
          return
        }
      }

      if (!res.ok) {
        const err = await res.json().catch(() => ({}))
        throw new Error(err.error || 'Speichern fehlgeschlagen')
      }

      const okData = await res.json().catch(() => null)
      if (okData && typeof okData.featuresVersion === 'number') {
        featuresVersionRef.current = okData.featuresVersion
      }

      // Broadcast features to other clients
      socketRef.current?.emit('features-updated', {
        projectId: currentProject.id,
        features,
      })
      addAudit(`Einsatz gespeichert (${features.length} Elemente)`)
      toast({
        title: 'Gespeichert',
        description: 'Änderungen wurden gespeichert.',
      })
    } catch (error) {
      toast({
        title: 'Fehler',
        description: error instanceof Error ? error.message : 'Einsatz konnte nicht gespeichert werden.',
        variant: 'destructive',
      })
    } finally {
      setIsSaving(false)
    }
  }

  // Einsatz beenden: speichern, Bearbeitungs-Lock lösen und zurück zur Übersicht.
  // Bestätigung erfolgt über einen In-App-Dialog (kein natives confirm()).
  const performEndProject = async () => {
    if (!currentProject) return
    setIsEndConfirmOpen(false)
    const title = currentProject.title
    try { await handleSaveProject() } catch { /* Save meldet Fehler selbst */ }
    if (isEditingByMe) { try { await handleStopEditing() } catch { /* ignore */ } }
    addAudit(`Einsatz "${title}" beendet`)
    setCurrentProject(null)
    setFeatures([])
    undoStackRef.current = []
    redoStackRef.current = []
    localStorage.removeItem('lageplan-project')
    toast({ title: 'Einsatz beendet', description: 'Gespeichert und geschlossen.' })
  }

  const handleFeaturesChange = useCallback((newFeatures: DrawFeature[]) => {
    undoStackRef.current.push(featuresRef.current)
    redoStackRef.current = []

    // Check if a new line/arrow/dangerzone was added → show label dialog
    if (newFeatures.length > featuresRef.current.length) {
      const added = newFeatures[newFeatures.length - 1]
      addAudit(`Element hinzugefügt: ${added.type} (${added.id.slice(0, 12)})`)

      if (added.type === 'linestring' || added.type === 'arrow' || added.type === 'dangerzone') {
        setFeatures(newFeatures)
        setPendingLineFeature(added)
        setIsLineLabelDialogOpen(true)
        broadcastFeatures(newFeatures)
        return
      }
    }

    setFeatures(newFeatures)
    broadcastFeatures(newFeatures)
  }, [addAudit, broadcastFeatures])

  const handleLineLabelConfirm = useCallback((label: string) => {
    if (pendingLineFeature && label) {
      setFeatures(prev => prev.map(f =>
        f.id === pendingLineFeature.id
          ? { ...f, properties: { ...f.properties, label } }
          : f
      ))
    }
    setPendingLineFeature(null)
    setIsLineLabelDialogOpen(false)
  }, [pendingLineFeature])

  const handleLineLabelSkip = useCallback(() => {
    setPendingLineFeature(null)
    setIsLineLabelDialogOpen(false)
  }, [])

  const handleSymbolDrop = useCallback((iconId: string, coordinates: [number, number], imageUrl?: string) => {
    const currentZoom = mapRef.current?.getZoom() || 17
    const newFeature: DrawFeature = {
      id: `symbol-${Date.now()}`,
      type: 'symbol',
      geometry: {
        type: 'Point',
        coordinates,
      },
      properties: {
        iconId,
        imageUrl: imageUrl || '',
        rotation: 0,
        scale: defaultSymbolScale,
        placementZoom: currentZoom,
      },
    }
    handleFeaturesChange([...featuresRef.current, newFeature])
  }, [handleFeaturesChange, defaultSymbolScale])

  // Tap-to-place: Symbol antippen → Sidebar schliessen, Karte zeigen, nächster Tipp platziert
  const handleSymbolSelect = useCallback((symbol: { id: string; imageUrl: string }) => {
    setPendingSymbol(symbol)
    setIsSidebarOpen(false)
    setActiveTab('map')
    setDrawMode('select')
    toast({ title: 'Symbol platzieren', description: 'Tippe auf die Karte, um das Symbol zu setzen.' })
  }, [setIsSidebarOpen, setActiveTab, toast])

  const handleTextPlace = useCallback((coordinates: [number, number]) => {
    setTextPlaceCoords(coordinates)
    setIsTextDialogOpen(true)
  }, [])

  const handleTextConfirm = useCallback((text: string, fontSize: number) => {
    if (!textPlaceCoords || !text.trim()) return
    const newFeature: DrawFeature = {
      id: `text-${Date.now()}`,
      type: 'text',
      geometry: {
        type: 'Point',
        coordinates: textPlaceCoords,
      },
      properties: {
        text,
        fontSize,
        color: selectedColor,
      },
    }
    handleFeaturesChange([...featuresRef.current, newFeature])
    setIsTextDialogOpen(false)
    setTextPlaceCoords(null)
  }, [textPlaceCoords, selectedColor, handleFeaturesChange])

  const handleUndo = useCallback(() => {
    // First try to undo a drawing point (during line/polygon creation)
    if (undoDrawPointRef.current && undoDrawPointRef.current()) {
      return
    }
    if (undoStackRef.current.length > 0) {
      const prev = undoStackRef.current.pop()!
      redoStackRef.current.push(featuresRef.current)
      setFeatures(prev)
    }
  }, [])

  const handleRedo = useCallback(() => {
    if (redoStackRef.current.length > 0) {
      const next = redoStackRef.current.pop()!
      undoStackRef.current.push(featuresRef.current)
      setFeatures(next)
    }
  }, [])

  // Keyboard shortcuts for tools
  const [isShortcutHelpOpen, setIsShortcutHelpOpen] = useState(false)
  useKeyboardShortcuts({
    featuresRef,
    onUndo: handleUndo,
    onRedo: handleRedo,
    onSave: handleSaveProject,
    onDelete: handleFeaturesChange,
    onToolChange: setDrawMode,
    onHelpOpen: useCallback(() => setIsShortcutHelpOpen(true), []),
  })

  const handlePlanUpload = useCallback(() => {
    if (!currentProject) return
    const input = document.createElement('input')
    input.type = 'file'
    input.accept = 'image/png,image/jpeg,image/webp,image/svg+xml'
    input.onchange = async () => {
      const file = input.files?.[0]
      if (!file) return
      // Use current map bounds as plan bounds
      const m = mapRef.current
      if (!m) return
      const bounds = m.getBounds()
      const planBounds = {
        north: bounds.getNorth(),
        south: bounds.getSouth(),
        east: bounds.getEast(),
        west: bounds.getWest(),
      }
      const formData = new FormData()
      formData.append('file', file)
      formData.append('bounds', JSON.stringify(planBounds))
      try {
        const res = await fetch(`/api/projects/${currentProject.id}/plan-image`, {
          method: 'POST',
          body: formData,
        })
        if (res.ok) {
          const data = await res.json()
          setCurrentProject(prev => prev ? { ...prev, planImageKey: data.planImageKey, planBounds: data.planBounds } : prev)
          toast({ title: 'Einsatzplan hochgeladen', description: 'Der Plan wird als Overlay auf der Karte angezeigt.' })
          addAudit('Einsatzplan hochgeladen')
        } else {
          const err = await res.json()
          toast({ title: 'Fehler', description: err.error || 'Upload fehlgeschlagen', variant: 'destructive' })
        }
      } catch {
        toast({ title: 'Fehler', description: 'Upload fehlgeschlagen', variant: 'destructive' })
      }
    }
    input.click()
  }, [currentProject, toast, addAudit])

  const handleDeleteAllRequest = useCallback(() => {
    if (featuresRef.current.length > 0) {
      setIsDeleteAllConfirmOpen(true)
    }
  }, [])

  const handleDeleteAllConfirm = useCallback(() => {
    if (featuresRef.current.length > 0) {
      undoStackRef.current.push(featuresRef.current)
      redoStackRef.current = []
      const count = featuresRef.current.length
      setFeatures([])
      addAudit(`Alle ${count} Elemente gelöscht`)
      toast({
        title: 'Alles gelöscht',
        description: `${count} Elemente wurden entfernt.`,
      })
    }
    setIsDeleteAllConfirmOpen(false)
  }, [toast, addAudit])

  const { handleExport } = useMapExport({
    mapRef,
    featuresRef,
    currentProject,
    tenant: tenant ? { id: tenant.id, name: tenant.name } : null,
    addAudit,
    toast: toast as any,
  })

  // Show loading state while checking auth
  if (authLoading || !user) {
    return (
      <div className="h-screen flex items-center justify-center bg-background">
        <div className="text-center">
          <div className="w-12 h-12 border-4 border-primary border-t-transparent rounded-full animate-spin mx-auto mb-4" />
          <p className="text-muted-foreground text-sm">Laden...</p>
        </div>
      </div>
    )
  }

  return (
    <DndProvider backend={MultiBackend} options={{ backends: [
        { id: 'html5', backend: HTML5Backend, transition: MouseTransition },
        { id: 'touch', backend: TouchBackend, options: { delayTouchStart: 150 }, transition: TouchTransition, preview: true },
      ] }}>
      <CustomDragLayer />
      <div className="h-screen flex flex-col overflow-hidden bg-background">
        <Topbar
          project={currentProject}
          onNewProject={handleNewProject}
          onEndProject={() => setIsEndConfirmOpen(true)}
          onSaveProject={handleSaveProject}
          onLoadProject={handleProjectLoaded}
          onDeleteProject={handleDeleteProject}
          onExport={handleExport}
          onClearAll={canEdit ? handleDeleteAllRequest : undefined}
          isSaving={isSaving}
          isDarkMode={isDarkMode}
          onToggleTheme={toggleTheme}
          isFullscreen={isFullscreen}
          onToggleFullscreen={toggleFullscreen}
          auditLog={auditLog}
          isAuditOpen={isAuditOpen}
          onToggleAudit={() => setIsAuditOpen(!isAuditOpen)}
          userName={user?.name}
          userRole={user?.role}
          onLogout={logout}
          onStartTour={() => { resetOnboardingTour(); setShowTour(true) }}
          presentationLocked={presentationLocked}
          onTogglePresentationLock={() => {
            const next = !presentationLocked
            setPresentationLocked(next)
            if (next && isEditingByMe) {
              handleStopEditing()
            }
          }}
        />

        {/* Übungs-Banner — verhindert Verwechslung mit echtem Einsatz */}
        {currentProject?.mode === 'UEBUNG' && (
          <div className="flex items-center justify-center gap-2 px-4 py-1 md:py-1.5 bg-blue-600 text-white text-xs md:text-sm font-semibold tracking-wide">
            <GraduationCap className="w-4 h-4 shrink-0" />
            <span>ÜBUNG — kein realer Einsatz</span>
          </div>
        )}

        {/* Offline banner */}
        {isOffline && (
          <div className="flex items-center justify-center gap-2 md:gap-3 px-3 md:px-4 py-1.5 md:py-2 bg-orange-50 dark:bg-orange-950/40 border-b border-orange-200 dark:border-orange-800 text-xs md:text-sm text-orange-800 dark:text-orange-300">
            <WifiOff className="w-4 h-4 shrink-0" />
            <span>
              <strong>Offline</strong><span className="hidden sm:inline">-Modus — Änderungen werden lokal gespeichert und beim Reconnect synchronisiert.</span>
              {syncQueueCount > 0 && ` (${syncQueueCount} ausstehend)`}
            </span>
          </div>
        )}

        {/* Email verification banner */}
        {user && user.emailVerified === false && (
          <div className="flex items-center justify-center gap-2 md:gap-3 px-3 md:px-4 py-1.5 md:py-2 bg-amber-50 dark:bg-amber-950/40 border-b border-amber-200 dark:border-amber-800 text-xs md:text-sm text-amber-800 dark:text-amber-300">
            <AlertTriangle className="w-4 h-4 shrink-0" />
            <span>E-Mail noch nicht bestätigt.<span className="hidden sm:inline"> Bitte prüfen Sie Ihren Posteingang.</span></span>
            <button
              onClick={async () => {
                try {
                  const res = await fetch('/api/auth/resend-verification', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ email: user.email }),
                  })
                  if (res.ok) toast({ title: 'Bestätigungsmail gesendet', description: 'Bitte prüfen Sie Ihren Posteingang.' })
                  else toast({ title: 'Fehler', description: 'Konnte Bestätigungsmail nicht senden.', variant: 'destructive' })
                } catch { toast({ title: 'Fehler', description: 'Verbindungsfehler.', variant: 'destructive' }) }
              }}
              className="shrink-0 text-xs font-semibold underline hover:no-underline text-amber-700 dark:text-amber-400"
            >
              Erneut senden
            </button>
          </div>
        )}

        {/* Live editing banner */}
        {currentProject && (
          <div className="flex items-center justify-between gap-2 px-3 md:px-4 py-1.5 bg-muted/50 border-b text-xs md:text-sm">
            {isReadOnly ? (
              <div className="flex items-center gap-2 text-orange-600 min-w-0">
                <Eye className="w-4 h-4 shrink-0" />
                <span className="truncate"><strong>{editingBy?.name}</strong> bearbeitet die Karte<span className="hidden sm:inline"> — Live-Ansicht{roleCanEdit ? ' · Journal bleibt für Sie bearbeitbar' : ''}</span></span>
              </div>
            ) : isEditingByMe ? (
              <div className="flex items-center gap-2 text-green-600 min-w-0">
                <Lock className="w-4 h-4 shrink-0" />
                <span className="truncate">Sie bearbeiten die Karte<span className="hidden sm:inline"> — andere sehen Ihre Änderungen in Echtzeit</span></span>
              </div>
            ) : (
              <div className="flex items-center gap-2 text-muted-foreground min-w-0">
                <Unlock className="w-4 h-4 shrink-0" />
                <span className="truncate">Niemand bearbeitet gerade</span>
              </div>
            )}
            <div data-tour="edit-toggle" className="flex items-center gap-2 shrink-0">
              {roleCanEdit && !isEditingByMe && !isReadOnly && (
                <Button size="sm" variant="default" onClick={handleStartEditing} disabled={editingLoading}>
                  <Lock className="w-3.5 h-3.5 mr-1" />
                  Bearbeitung starten
                </Button>
              )}
              {isEditingByMe && (
                <Button size="sm" variant="outline" onClick={handleStopEditing} disabled={editingLoading}>
                  <Unlock className="w-3.5 h-3.5 mr-1" />
                  Bearbeitung beenden
                </Button>
              )}
            </div>
          </div>
        )}

        <div className="flex-1 flex overflow-hidden">
          {/* Map view — always mounted, hidden via CSS to preserve state */}
          <div data-tour="toolbar" className={`contents ${activeTab !== 'map' ? 'hidden' : ''}`}>
            <LeftToolbar
              drawMode={drawMode || 'select'}
              onDrawModeChange={setDrawMode}
              selectedColor={selectedColor}
              onColorChange={setSelectedColor}
              selectedWidth={selectedWidth}
              onWidthChange={setSelectedWidth}
              onUndo={handleUndo}
              onRedo={handleRedo}
              canEdit={canEdit}
            />
          </div>

          <div className={`flex-1 overflow-hidden ${activeTab !== 'map' ? 'hidden' : ''}`}>
            <main className="w-full h-full relative">
              <MapView
                project={currentProject}
                features={features}
                drawMode={drawMode || 'select'}
                selectedColor={selectedColor}
                selectedWidth={selectedWidth}
                onFeaturesChange={handleFeaturesChange}
                onSymbolDrop={handleSymbolDrop}
                onTextPlace={handleTextPlace}
                canEdit={canEdit}
                mapRef={mapRef}
                onDrawModeChange={setDrawMode}
                undoDrawPointRef={undoDrawPointRef}
                pendingSymbol={pendingSymbol ? { iconId: pendingSymbol.id, imageUrl: pendingSymbol.imageUrl } : null}
                onSymbolPlaced={() => setPendingSymbol(null)}
              />
            </main>
          </div>

          {/* Journal / Übungs-Cockpit — always mounted, hidden via CSS */}
          <main className={`flex-1 flex flex-col min-h-0 bg-background pb-14 md:pb-0 ${activeTab !== 'journal' ? 'hidden' : ''}`}>
            {currentProject?.mode === 'UEBUNG' ? (
              <ExerciseCockpit
                projectId={currentProject?.id || null}
                projectTitle={currentProject?.title || ''}
                canEdit={canEditJournal}
                initialEvaluation={currentProject?.exerciseEvaluation || ''}
                onEvaluationSaved={(value) =>
                  setCurrentProject((prev) => (prev ? { ...prev, exerciseEvaluation: value } : prev))
                }
              />
            ) : (
              <JournalView
                projectId={currentProject?.id || null}
                projectTitle={currentProject?.title || ''}
                projectLocation={currentProject?.location || ''}
                mode={currentProject?.mode}
                einsatzleiter={currentProject?.einsatzleiter || ''}
                journalfuehrer={currentProject?.journalfuehrer || ''}
                einsatzNr={(currentProject as any)?.einsatzNr || ''}
                canEdit={canEditJournal}
                tenantId={tenant?.id || null}
                tenantName={tenant?.name || ''}
                tenantLogoUrl={tenant?.id ? `/api/admin/tenants/${tenant.id}/logo/serve` : null}
                mapRef={mapRef}
                mapScreenshot={lastMapScreenshot}
              />
            )}
          </main>

          {/* Right sidebar — always visible, contains Karte/Journal tabs */}
          <RightSidebar
            data-tour="sidebar"
            onSymbolDrop={handleSymbolDrop}
            onSymbolSelect={handleSymbolSelect}
            canEdit={canEdit}
            isOpen={isSidebarOpen}
            onToggle={() => setIsSidebarOpen(!isSidebarOpen)}
            activeTab={activeTab}
            onTabChange={handleTabChange}
            isCollapsed={isSidebarCollapsed}
            onToggleCollapse={() => setIsSidebarCollapsed(!isSidebarCollapsed)}
            tenantId={tenant?.id || null}
            mode={currentProject?.mode}
          />
        </div>

        {/* Tap-to-place Hinweis — schwebt über der Bottom-Nav, mit Abbrechen */}
        {pendingSymbol && (
          <div className="fixed left-1/2 -translate-x-1/2 z-40 bottom-[76px] md:bottom-6 flex items-center gap-2 px-3 py-2 rounded-full bg-primary text-primary-foreground shadow-lg text-sm">
            <img src={pendingSymbol.imageUrl} alt="" className="w-5 h-5 object-contain bg-white rounded" crossOrigin="anonymous" />
            <span>Auf die Karte tippen zum Platzieren</span>
            <button onClick={() => setPendingSymbol(null)} className="ml-1 p-0.5 rounded-full hover:bg-white/20" title="Abbrechen">
              <X className="w-4 h-4" />
            </button>
          </div>
        )}

        {/* Mobile Bottom-Navigation — Karte / Journal / Symbole erreichbar ohne Menü */}
        {currentProject && (
          <nav className="md:hidden fixed bottom-0 left-0 right-0 z-30 flex items-stretch border-t border-border bg-card shadow-[0_-2px_8px_rgba(0,0,0,0.08)] pb-[env(safe-area-inset-bottom,0px)]">
            <button
              onClick={() => handleTabChange('map')}
              className={`flex-1 flex flex-col items-center justify-center gap-0.5 py-2 text-[11px] font-medium transition-colors ${
                activeTab === 'map' ? 'text-primary' : 'text-muted-foreground'
              }`}
            >
              <MapIcon className="w-5 h-5" />
              Karte
            </button>
            <button
              onClick={() => handleTabChange('journal')}
              className={`flex-1 flex flex-col items-center justify-center gap-0.5 py-2 text-[11px] font-medium transition-colors ${
                activeTab === 'journal' ? 'text-primary' : 'text-muted-foreground'
              }`}
            >
              <ClipboardList className="w-5 h-5" />
              {currentProject.mode === 'UEBUNG' ? 'Auswertung' : 'Journal'}
            </button>
            <button
              onClick={() => { handleTabChange('map'); setIsSidebarOpen(true) }}
              className="flex-1 flex flex-col items-center justify-center gap-0.5 py-2 text-[11px] font-medium text-muted-foreground transition-colors"
            >
              <LayoutGrid className="w-5 h-5" />
              Symbole
            </button>
          </nav>
        )}

        <ProjectDialog
          open={isProjectDialogOpen}
          onOpenChange={setIsProjectDialogOpen}
          onProjectCreated={handleProjectCreated}
          initialMode={newProjectMode}
        />

        {/* Einsatz beenden — In-App-Bestätigung statt native confirm() */}
        <Dialog open={isEndConfirmOpen} onOpenChange={setIsEndConfirmOpen}>
          <DialogContent className="max-w-sm">
            <DialogHeader>
              <DialogTitle>{currentProject?.mode === 'UEBUNG' ? 'Übung beenden?' : 'Einsatz beenden?'}</DialogTitle>
            </DialogHeader>
            <p className="text-sm text-muted-foreground">
              {currentProject?.title
                ? <>„{currentProject.title}" wird gespeichert und geschlossen.</>
                : 'Der aktuelle Eintrag wird gespeichert und geschlossen.'}
            </p>
            <DialogFooter>
              <Button variant="outline" onClick={() => setIsEndConfirmOpen(false)}>Abbrechen</Button>
              <Button
                className="bg-red-600 hover:bg-red-700 text-white"
                onClick={performEndProject}
              >
                {currentProject?.mode === 'UEBUNG' ? 'Übung beenden' : 'Einsatz beenden'}
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>

        <TextDialog
          open={isTextDialogOpen}
          onOpenChange={setIsTextDialogOpen}
          onConfirm={handleTextConfirm}
          selectedColor={selectedColor}
        />

        <LineLabelDialog
          open={isLineLabelDialogOpen}
          onOpenChange={setIsLineLabelDialogOpen}
          onConfirm={handleLineLabelConfirm}
          onSkip={handleLineLabelSkip}
          lineType={(pendingLineFeature?.type as any) || 'linestring'}
        />

        {/* Keyboard Shortcuts Help Dialog */}
        <Dialog open={isShortcutHelpOpen} onOpenChange={setIsShortcutHelpOpen}>
          <DialogContent className="max-w-md">
            <DialogHeader>
              <DialogTitle>Tastenkürzel</DialogTitle>
            </DialogHeader>
            <div className="grid grid-cols-2 gap-x-6 gap-y-1.5 text-sm mt-2">
              <div className="font-semibold text-muted-foreground col-span-2 mt-1 mb-0.5">Werkzeuge</div>
              {[
                ['V', 'Auswählen'], ['P', 'Punkt'], ['L', 'Linie'], ['G', 'Polygon'],
                ['R', 'Rechteck'], ['C', 'Kreis'], ['F', 'Freihand'], ['A', 'Pfeil / Route'],
                ['T', 'Text'], ['E', 'Radiergummi'], ['M', 'Messen'], ['D', 'Gefahrenzone'],
              ].map(([key, label]) => (
                <div key={key} className="flex items-center justify-between">
                  <span>{label}</span>
                  <kbd className="ml-2 px-1.5 py-0.5 bg-muted rounded border border-border font-mono text-xs">{key}</kbd>
                </div>
              ))}
              <div className="font-semibold text-muted-foreground col-span-2 mt-3 mb-0.5">Aktionen</div>
              {[
                ['Ctrl+Z', 'Rückgängig'], ['Ctrl+Y', 'Wiederholen'],
                ['Ctrl+S', 'Speichern'], ['Del', 'Auswahl löschen'],
                ['Esc', 'Abbrechen'], ['?', 'Diese Hilfe'],
              ].map(([key, label]) => (
                <div key={key} className="flex items-center justify-between">
                  <span>{label}</span>
                  <kbd className="ml-2 px-1.5 py-0.5 bg-muted rounded border border-border font-mono text-xs">{key}</kbd>
                </div>
              ))}
            </div>
          </DialogContent>
        </Dialog>

        {/* Delete All Confirmation Dialog */}
        <Dialog open={isDeleteAllConfirmOpen} onOpenChange={setIsDeleteAllConfirmOpen}>
          <DialogContent className="max-w-sm">
            <DialogHeader>
              <DialogTitle>Alles löschen?</DialogTitle>
            </DialogHeader>
            <p className="text-sm text-muted-foreground">
              Alle {features.length} Zeichnungen und Symbole werden entfernt. Diese Aktion kann mit Rückgängig wiederhergestellt werden.
            </p>
            <div className="flex gap-3 mt-2">
              <Button variant="outline" className="flex-1 h-12 text-base" onClick={() => setIsDeleteAllConfirmOpen(false)}>
                Abbrechen
              </Button>
              <Button variant="destructive" className="flex-1 h-12 text-base font-semibold" onClick={handleDeleteAllConfirm}>
                Alles löschen
              </Button>
            </div>
          </DialogContent>
        </Dialog>

        {/* Onboarding Tour */}
        <OnboardingTour
          forceShow={showTour}
          onComplete={() => setShowTour(false)}
        />
      </div>
    </DndProvider>
  )
}
