import { useCallback, useEffect, useRef } from 'react'
import type { DrawFeature, Project } from '@/types'
import { addToSyncQueue, getSyncQueue } from '@/lib/offline-sync'

interface UseAutoSaveOptions {
  currentProject: Project | null
  features: DrawFeature[]
  featuresRef: React.MutableRefObject<DrawFeature[]>
  mapRef: React.MutableRefObject<any>
  socketRef: React.MutableRefObject<any>
  isEditingByMe: boolean
  setSyncQueueCount: (count: number) => void
  /** Aktuelle Features-Version des Projekts (optimistischer Lock) */
  featuresVersionRef: React.MutableRefObject<number>
  /** Wird bei einem Speicher-Konflikt (409) mit dem Server-Stand aufgerufen */
  onConflict: (serverFeatures: DrawFeature[], serverVersion: number) => void
}

export function useAutoSave({
  currentProject,
  features,
  featuresRef,
  mapRef,
  socketRef,
  isEditingByMe,
  setSyncQueueCount,
  featuresVersionRef,
  onConflict,
}: UseAutoSaveOptions) {
  // Persist features to localStorage on change (per project — verhindert, dass Features
  // eines Projekts in ein anderes "bluten"). Inkl. leerem Array (spiegelt Löschungen).
  useEffect(() => {
    if (!currentProject?.id) return
    localStorage.setItem(`lageplan-features-${currentProject.id}`, JSON.stringify(features))
  }, [features, currentProject?.id])

  // Auto-save to API — debounced 2s after every feature change + fallback interval
  const saveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const saveFeaturesToApi = useCallback(async () => {
    if (!currentProject?.id) return
    const url = `/api/projects/${currentProject.id}/features`
    const mapInstance = mapRef.current
    const body: any = { features: featuresRef.current, baseVersion: featuresVersionRef.current }
    if (mapInstance) {
      const c = mapInstance.getCenter()
      body.mapCenter = { lng: c.lng, lat: c.lat }
      body.mapZoom = mapInstance.getZoom()
    }

    // If offline, queue the save for later sync
    if (!navigator.onLine) {
      addToSyncQueue(url, 'PUT', body)
      setSyncQueueCount(getSyncQueue().length)
      console.log('[Auto-Save] Offline — in Sync-Queue gespeichert')
      return
    }

    try {
      const res = await fetch(url, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      })
      if (res.ok) {
        const data = await res.json().catch(() => null)
        if (data && typeof data.featuresVersion === 'number') {
          featuresVersionRef.current = data.featuresVersion
        }
        console.log('[Auto-Save] Features gespeichert')
        socketRef.current?.emit('features-updated', {
          projectId: currentProject.id,
          features: featuresRef.current,
        })
      } else if (res.status === 409) {
        // Konflikt: jemand anderes hat zwischenzeitlich gespeichert → Server-Stand übernehmen
        const data = await res.json().catch(() => null)
        if (data?.conflict) {
          console.warn('[Auto-Save] Versionskonflikt — Server-Stand übernehmen')
          onConflict(data.features || [], data.featuresVersion ?? featuresVersionRef.current)
        }
      } else if (res.status === 404) {
        console.warn('[Auto-Save] Projekt nicht in DB')
      }
    } catch (e) {
      // Network error — queue for later
      addToSyncQueue(url, 'PUT', body)
      setSyncQueueCount(getSyncQueue().length)
      console.warn('[Auto-Save] Netzwerkfehler — in Sync-Queue:', e)
    }
  }, [currentProject, mapRef, featuresRef, socketRef, setSyncQueueCount, featuresVersionRef, onConflict])

  // Debounced save on every feature change (2s delay)
  useEffect(() => {
    if (!currentProject || !isEditingByMe) return
    if (saveTimerRef.current) clearTimeout(saveTimerRef.current)
    saveTimerRef.current = setTimeout(() => saveFeaturesToApi(), 2000)
    return () => { if (saveTimerRef.current) clearTimeout(saveTimerRef.current) }
  }, [features, currentProject, isEditingByMe, saveFeaturesToApi])

  // Also save on page unload / tab switch
  useEffect(() => {
    const handleBeforeUnload = () => {
      // Nur der aktive Bearbeiter persistiert beim Schliessen — auch eine leere Liste,
      // damit "alles gelöscht + Tab zu" nicht die alten Elemente in der DB stehen lässt.
      if (currentProject?.id && isEditingByMe) {
        const payload = JSON.stringify({ features: featuresRef.current, baseVersion: featuresVersionRef.current })
        navigator.sendBeacon(`/api/projects/${currentProject.id}/features`, new Blob([payload], { type: 'application/json' }))
      }
    }
    const handleVisibilityChange = () => {
      if (document.visibilityState === 'hidden' && currentProject?.id && isEditingByMe) {
        saveFeaturesToApi()
      }
    }
    window.addEventListener('beforeunload', handleBeforeUnload)
    document.addEventListener('visibilitychange', handleVisibilityChange)
    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload)
      document.removeEventListener('visibilitychange', handleVisibilityChange)
    }
  }, [currentProject, isEditingByMe, saveFeaturesToApi, featuresRef])
}
