'use client'

import React, { createContext, useReducer, useEffect, useCallback, useMemo, useRef } from 'react'
import { useRouter, usePathname } from 'next/navigation'
import {
  SDKState,
  CheckpointStatus,
  UseCaseAssessment,
  Risk,
  Control,
  CustomerType,
  CompanyProfile,
  ImportedDocument,
  GapAnalysis,
  SDKPackageId,
  ProjectInfo,
  getStepById,
  getStepByUrl,
  getNextStep,
  getPreviousStep,
  getCompletionPercentage,
  getPhaseCompletionPercentage,
  getPackageCompletionPercentage,
} from './types'
import { exportToPDF, exportToZIP } from './export'
import { SDKApiClient, getSDKApiClient } from './api-client'
import { StateSyncManager, SyncState } from './sync'
import { generateDemoState } from './demo-data'
import { SDKContextValue, initialState, SDK_STORAGE_KEY } from './context-types'
import { sdkReducer } from './context-reducer'
import { validateCheckpointLocally } from './context-validators'
import {
  ensureApiClient,
  createProjectApi,
  listProjectsApi,
  archiveProjectApi,
  restoreProjectApi,
  permanentlyDeleteProjectApi,
} from './context-projects'
import {
  buildSyncCallbacks,
  loadInitialState,
  initSyncInfra,
  cleanupSyncInfra,
} from './context-sync-helpers'

export const SDKContext = createContext<SDKContextValue | null>(null)

interface SDKProviderProps {
  children: React.ReactNode
  tenantId?: string
  userId?: string
  projectId?: string
  enableBackendSync?: boolean
}

export function SDKProvider({
  children,
  tenantId = '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e',
  userId = 'default',
  projectId,
  enableBackendSync = false,
}: SDKProviderProps) {
  const router = useRouter()
  const pathname = usePathname()
  const [state, dispatch] = useReducer(sdkReducer, {
    ...initialState,
    tenantId,
    userId,
    projectId: projectId || '',
  })
  const [isCommandBarOpen, setCommandBarOpen] = React.useState(false)
  const [isInitialized, setIsInitialized] = React.useState(false)
  const [syncState, setSyncState] = React.useState<SyncState>({
    status: 'idle',
    lastSyncedAt: null,
    localVersion: 0,
    serverVersion: 0,
    pendingChanges: 0,
    error: null,
  })
  const [isOnline, setIsOnline] = React.useState(true)

  // Refs for sync manager and API client
  const apiClientRef = useRef<SDKApiClient | null>(null)
  const syncManagerRef = useRef<StateSyncManager | null>(null)
  const stateRef = useRef(state)
  stateRef.current = state

  // Initialize API client and sync manager
  useEffect(() => {
    const callbacks = buildSyncCallbacks(setSyncState, setIsOnline, dispatch, stateRef)
    initSyncInfra(enableBackendSync, tenantId, projectId, apiClientRef, syncManagerRef, callbacks)
    return () => cleanupSyncInfra(enableBackendSync, syncManagerRef, apiClientRef)
  }, [enableBackendSync, tenantId, projectId])

  // Sync current step with URL
  useEffect(() => {
    if (pathname) {
      const step = getStepByUrl(pathname)
      if (step && step.id !== state.currentStep) {
        dispatch({ type: 'SET_CURRENT_STEP', payload: step.id })
      }
    }
  }, [pathname, state.currentStep])

  // Storage key — per tenant+project
  const storageKey = projectId
    ? `${SDK_STORAGE_KEY}-${tenantId}-${projectId}`
    : `${SDK_STORAGE_KEY}-${tenantId}`

  // Load state on mount (localStorage first, then server)
  useEffect(() => {
    loadInitialState({
      storageKey,
      enableBackendSync,
      projectId,
      syncManager: syncManagerRef.current,
      apiClient: apiClientRef.current,
      dispatch,
    })
      .catch(error => console.error('Failed to load SDK state:', error))
      .finally(() => setIsInitialized(true))
  }, [tenantId, projectId, enableBackendSync, storageKey])

  // Auto-save to localStorage and sync to server
  useEffect(() => {
    if (!isInitialized || !state.preferences.autoSave) return

    const saveTimeout = setTimeout(() => {
      try {
        // Save to localStorage (per tenant+project)
        localStorage.setItem(storageKey, JSON.stringify(state))

        // Sync to server if backend sync is enabled
        if (enableBackendSync && syncManagerRef.current) {
          syncManagerRef.current.queueSync(state)
        }
      } catch (error) {
        console.error('Failed to save SDK state:', error)
      }
    }, 1000)

    return () => clearTimeout(saveTimeout)
  }, [state, tenantId, projectId, isInitialized, enableBackendSync, storageKey])

  // Keyboard shortcut for Command Bar
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
        e.preventDefault()
        setCommandBarOpen(prev => !prev)
      }
      if (e.key === 'Escape' && isCommandBarOpen) {
        setCommandBarOpen(false)
      }
    }

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

  // Navigation
  const currentStep = useMemo(() => getStepById(state.currentStep), [state.currentStep])

  const goToStep = useCallback(
    (stepId: string) => {
      const step = getStepById(stepId)
      if (step) {
        dispatch({ type: 'SET_CURRENT_STEP', payload: stepId })
        const url = projectId ? `${step.url}?project=${projectId}` : step.url
        router.push(url)
      }
    },
    [router, projectId]
  )

  const goToNextStep = useCallback(() => {
    const nextStep = getNextStep(state.currentStep, state)
    if (nextStep) {
      goToStep(nextStep.id)
    }
  }, [state, goToStep])

  const goToPreviousStep = useCallback(() => {
    const prevStep = getPreviousStep(state.currentStep, state)
    if (prevStep) {
      goToStep(prevStep.id)
    }
  }, [state, goToStep])

  const canGoNext = useMemo(() => {
    return getNextStep(state.currentStep, state) !== undefined
  }, [state])

  const canGoPrevious = useMemo(() => {
    return getPreviousStep(state.currentStep, state) !== undefined
  }, [state])

  // Progress
  const completionPercentage = useMemo(() => getCompletionPercentage(state), [state])
  const phase1Completion = useMemo(() => getPhaseCompletionPercentage(state, 1), [state])
  const phase2Completion = useMemo(() => getPhaseCompletionPercentage(state, 2), [state])

  // Package Completion
  const packageCompletion = useMemo(() => {
    const completion: Record<SDKPackageId, number> = {
      'vorbereitung': getPackageCompletionPercentage(state, 'vorbereitung'),
      'analyse': getPackageCompletionPercentage(state, 'analyse'),
      'dokumentation': getPackageCompletionPercentage(state, 'dokumentation'),
      'rechtliche-texte': getPackageCompletionPercentage(state, 'rechtliche-texte'),
      'betrieb': getPackageCompletionPercentage(state, 'betrieb'),
    }
    return completion
  }, [state])

  // Simple dispatch callbacks
  const setCustomerType = useCallback((type: CustomerType) => dispatch({ type: 'SET_CUSTOMER_TYPE', payload: type }), [])
  const setCompanyProfile = useCallback((profile: CompanyProfile) => dispatch({ type: 'SET_COMPANY_PROFILE', payload: profile }), [])
  const updateCompanyProfile = useCallback((updates: Partial<CompanyProfile>) => dispatch({ type: 'UPDATE_COMPANY_PROFILE', payload: updates }), [])
  const setComplianceScope = useCallback((scope: import('./compliance-scope-types').ComplianceScopeState) => dispatch({ type: 'SET_COMPLIANCE_SCOPE', payload: scope }), [])
  const updateComplianceScope = useCallback((updates: Partial<import('./compliance-scope-types').ComplianceScopeState>) => dispatch({ type: 'UPDATE_COMPLIANCE_SCOPE', payload: updates }), [])
  const addImportedDocument = useCallback((doc: ImportedDocument) => dispatch({ type: 'ADD_IMPORTED_DOCUMENT', payload: doc }), [])
  const setGapAnalysis = useCallback((analysis: GapAnalysis) => dispatch({ type: 'SET_GAP_ANALYSIS', payload: analysis }), [])

  // Checkpoints
  const validateCheckpoint = useCallback(
    async (checkpointId: string): Promise<CheckpointStatus> => {
      // Try backend validation if available
      if (enableBackendSync && apiClientRef.current) {
        try {
          const result = await apiClientRef.current.validateCheckpoint(checkpointId, state)
          const status: CheckpointStatus = {
            checkpointId: result.checkpointId,
            passed: result.passed,
            validatedAt: new Date(result.validatedAt),
            validatedBy: result.validatedBy,
            errors: result.errors,
            warnings: result.warnings,
          }
          dispatch({ type: 'SET_CHECKPOINT_STATUS', payload: { id: checkpointId, status } })
          return status
        } catch {
          // Fall back to local validation
        }
      }

      // Local validation
      const status = validateCheckpointLocally(checkpointId, state)

      dispatch({ type: 'SET_CHECKPOINT_STATUS', payload: { id: checkpointId, status } })
      return status
    },
    [state, enableBackendSync]
  )

  const overrideCheckpoint = useCallback(async (checkpointId: string, reason: string): Promise<void> => {
    const existing = state.checkpoints[checkpointId]
    const overridden: CheckpointStatus = {
      ...existing, checkpointId, passed: true, overrideReason: reason,
      overriddenBy: state.userId, overriddenAt: new Date(),
      errors: [], warnings: existing?.warnings || [],
    }
    dispatch({ type: 'SET_CHECKPOINT_STATUS', payload: { id: checkpointId, status: overridden } })
  }, [state.checkpoints, state.userId])

  const getCheckpointStatus = useCallback(
    (checkpointId: string) => state.checkpoints[checkpointId],
    [state.checkpoints]
  )

  const updateUseCase = useCallback((id: string, data: Partial<UseCaseAssessment>) => dispatch({ type: 'UPDATE_USE_CASE', payload: { id, data } }), [])
  const addRisk = useCallback((risk: Risk) => dispatch({ type: 'ADD_RISK', payload: risk }), [])
  const updateControl = useCallback((id: string, data: Partial<Control>) => dispatch({ type: 'UPDATE_CONTROL', payload: { id, data } }), [])
  const loadDemoData = useCallback((demoState: Partial<SDKState>) => dispatch({ type: 'LOAD_DEMO_DATA', payload: demoState }), [])

  // Seed demo data via API (stores like real customer data)
  const seedDemoData = useCallback(async (): Promise<{ success: boolean; message: string }> => {
    try {
      // Generate demo state
      const demoState = generateDemoState(tenantId, userId) as SDKState

      // Save via API (same path as real customer data)
      if (enableBackendSync && apiClientRef.current) {
        await apiClientRef.current.saveState(demoState)
      }

      // Also save to localStorage for immediate availability
      localStorage.setItem(storageKey, JSON.stringify(demoState))

      // Update local state
      dispatch({ type: 'LOAD_DEMO_DATA', payload: demoState })

      return { success: true, message: `Demo-Daten erfolgreich geladen für Tenant ${tenantId}` }
    } catch (error) {
      console.error('Failed to seed demo data:', error)
      return {
        success: false,
        message: error instanceof Error ? error.message : 'Unbekannter Fehler beim Laden der Demo-Daten',
      }
    }
  }, [tenantId, userId, enableBackendSync, storageKey])

  // Clear demo data
  const clearDemoData = useCallback(async (): Promise<boolean> => {
    try {
      // Delete from API
      if (enableBackendSync && apiClientRef.current) {
        await apiClientRef.current.deleteState()
      }

      // Clear localStorage
      localStorage.removeItem(storageKey)

      // Reset local state
      dispatch({ type: 'RESET_STATE' })

      return true
    } catch (error) {
      console.error('Failed to clear demo data:', error)
      return false
    }
  }, [storageKey, enableBackendSync])

  // Check if demo data is loaded (has use cases with demo- prefix)
  const isDemoDataLoaded = useMemo(() => {
    return state.useCases.length > 0 && state.useCases.some(uc => uc.id.startsWith('demo-'))
  }, [state.useCases])

  // Persistence
  const saveState = useCallback(async (): Promise<void> => {
    try {
      localStorage.setItem(storageKey, JSON.stringify(state))

      if (enableBackendSync && syncManagerRef.current) {
        await syncManagerRef.current.forcSync(state)
      }
    } catch (error) {
      console.error('Failed to save SDK state:', error)
      throw error
    }
  }, [state, storageKey, enableBackendSync])

  const loadState = useCallback(async (): Promise<void> => {
    try {
      if (enableBackendSync && syncManagerRef.current) {
        const serverState = await syncManagerRef.current.loadFromServer()
        if (serverState) {
          dispatch({ type: 'SET_STATE', payload: serverState })
          return
        }
      }

      // Fall back to localStorage
      const stored = localStorage.getItem(storageKey)
      if (stored) {
        const parsed = JSON.parse(stored)
        dispatch({ type: 'SET_STATE', payload: parsed })
      }
    } catch (error) {
      console.error('Failed to load SDK state:', error)
      throw error
    }
  }, [storageKey, enableBackendSync])

  // Force sync to server
  const forceSyncToServer = useCallback(async (): Promise<void> => {
    if (enableBackendSync && syncManagerRef.current) {
      await syncManagerRef.current.forcSync(state)
    }
  }, [state, enableBackendSync])

  // Project Management
  const createProject = useCallback(
    async (name: string, customerType: CustomerType, copyFromProjectId?: string): Promise<ProjectInfo> => {
      const client = ensureApiClient(apiClientRef, enableBackendSync, tenantId, projectId)
      return createProjectApi(client, name, customerType, copyFromProjectId)
    },
    [enableBackendSync, tenantId, projectId]
  )

  const listProjectsFn = useCallback(async (): Promise<ProjectInfo[]> => {
    if (!apiClientRef.current && enableBackendSync) {
      apiClientRef.current = getSDKApiClient(tenantId, projectId)
    }
    if (!apiClientRef.current) {
      return []
    }
    return listProjectsApi(apiClientRef.current)
  }, [enableBackendSync, tenantId, projectId])

  const switchProject = useCallback(
    (newProjectId: string) => {
      const params = new URLSearchParams(window.location.search)
      params.set('project', newProjectId)
      router.push(`/sdk?${params.toString()}`)
    },
    [router]
  )

  const archiveProjectFn = useCallback(
    async (archiveId: string): Promise<void> => {
      const client = ensureApiClient(apiClientRef, enableBackendSync, tenantId, projectId)
      await archiveProjectApi(client, archiveId)
    },
    [enableBackendSync, tenantId, projectId]
  )

  const restoreProjectFn = useCallback(
    async (restoreId: string): Promise<ProjectInfo> => {
      const client = ensureApiClient(apiClientRef, enableBackendSync, tenantId, projectId)
      return restoreProjectApi(client, restoreId)
    },
    [enableBackendSync, tenantId, projectId]
  )

  const permanentlyDeleteProjectFn = useCallback(
    async (deleteId: string): Promise<void> => {
      const client = ensureApiClient(apiClientRef, enableBackendSync, tenantId, projectId)
      await permanentlyDeleteProjectApi(client, deleteId)
    },
    [enableBackendSync, tenantId, projectId]
  )

  // Export
  const exportState = useCallback(
    async (format: 'json' | 'pdf' | 'zip'): Promise<Blob> => {
      switch (format) {
        case 'json':
          return new Blob([JSON.stringify(state, null, 2)], {
            type: 'application/json',
          })

        case 'pdf':
          return exportToPDF(state)

        case 'zip':
          return exportToZIP(state)

        default:
          throw new Error(`Unknown export format: ${format}`)
      }
    },
    [state]
  )

  const value: SDKContextValue = {
    state,
    dispatch,
    currentStep,
    goToStep,
    goToNextStep,
    goToPreviousStep,
    canGoNext,
    canGoPrevious,
    completionPercentage,
    phase1Completion,
    phase2Completion,
    packageCompletion,
    setCustomerType,
    setCompanyProfile,
    updateCompanyProfile,
    setComplianceScope,
    updateComplianceScope,
    addImportedDocument,
    setGapAnalysis,
    validateCheckpoint,
    overrideCheckpoint,
    getCheckpointStatus,
    updateUseCase,
    addRisk,
    updateControl,
    saveState,
    loadState,
    loadDemoData,
    seedDemoData,
    clearDemoData,
    isDemoDataLoaded,
    syncState,
    forceSyncToServer,
    isOnline,
    exportState,
    isCommandBarOpen,
    setCommandBarOpen,
    projectId,
    createProject,
    listProjects: listProjectsFn,
    switchProject,
    archiveProject: archiveProjectFn,
    restoreProject: restoreProjectFn,
    permanentlyDeleteProject: permanentlyDeleteProjectFn,
  }

  return <SDKContext.Provider value={value}>{children}</SDKContext.Provider>
}
