'use client'

import React, {
  createContext,
  useContext,
  useReducer,
  useEffect,
  useCallback,
  useMemo,
  useRef,
  useState,
} from 'react'
import {
  ComplianceClient,
  sdkReducer,
  initialState,
  StateSyncManager,
  createStateSyncManager,
  createDSGVOModule,
  createComplianceModule,
  createRAGModule,
  createSecurityModule,
  type DSGVOModule,
  type ComplianceModule,
  type RAGModule,
  type SecurityModule,
} from '@breakpilot/compliance-sdk-core'
import type {
  SDKState,
  SDKAction,
  SDKStep,
  CheckpointStatus,
  SyncState,
  UseCaseAssessment,
  Risk,
  Control,
  UserPreferences,
} from '@breakpilot/compliance-sdk-types'
import {
  getStepById,
  getNextStep,
  getPreviousStep,
  getCompletionPercentage,
  getPhaseCompletionPercentage,
} from '@breakpilot/compliance-sdk-types'

// =============================================================================
// CONTEXT TYPES
// =============================================================================

export interface ComplianceContextValue {
  // State
  state: SDKState
  dispatch: React.Dispatch<SDKAction>

  // Client
  client: ComplianceClient

  // Modules
  dsgvo: DSGVOModule
  compliance: ComplianceModule
  rag: RAGModule
  security: SecurityModule

  // Navigation
  currentStep: SDKStep | undefined
  goToStep: (stepId: string) => void
  goToNextStep: () => void
  goToPreviousStep: () => void
  canGoNext: boolean
  canGoPrevious: boolean

  // Progress
  completionPercentage: number
  phase1Completion: number
  phase2Completion: number

  // Checkpoints
  validateCheckpoint: (checkpointId: string) => Promise<CheckpointStatus>
  overrideCheckpoint: (checkpointId: string, reason: string) => Promise<void>
  getCheckpointStatus: (checkpointId: string) => CheckpointStatus | undefined

  // State Updates
  updateUseCase: (id: string, data: Partial<UseCaseAssessment>) => void
  addRisk: (risk: Risk) => void
  updateControl: (id: string, data: Partial<Control>) => void

  // Persistence
  saveState: () => Promise<void>
  loadState: () => Promise<void>
  resetState: () => void

  // Sync
  syncState: SyncState
  forceSyncToServer: () => Promise<void>
  isOnline: boolean

  // Export
  exportState: (format: 'json' | 'pdf' | 'zip') => Promise<Blob>

  // Command Bar
  isCommandBarOpen: boolean
  setCommandBarOpen: (open: boolean) => void

  // Status
  isInitialized: boolean
  isLoading: boolean
  error: Error | null
}

export const ComplianceContext = createContext<ComplianceContextValue | null>(null)

// =============================================================================
// PROVIDER PROPS
// =============================================================================

export interface ComplianceProviderProps {
  children: React.ReactNode
  apiEndpoint: string
  apiKey?: string
  tenantId: string
  userId?: string
  enableBackendSync?: boolean
  onNavigate?: (url: string) => void
  onError?: (error: Error) => void
}

// =============================================================================
// PROVIDER
// =============================================================================

const SDK_STORAGE_KEY = 'breakpilot-compliance-sdk-state'

export function ComplianceProvider({
  children,
  apiEndpoint,
  apiKey,
  tenantId,
  userId = 'default',
  enableBackendSync = true,
  onNavigate,
  onError,
}: ComplianceProviderProps) {
  const [state, dispatch] = useReducer(sdkReducer, {
    ...initialState,
    tenantId,
    userId,
  })
  const [isCommandBarOpen, setCommandBarOpen] = useState(false)
  const [isInitialized, setIsInitialized] = useState(false)
  const [isLoading, setIsLoading] = useState(true)
  const [error, setError] = useState<Error | null>(null)
  const [syncState, setSyncState] = useState<SyncState>({
    status: 'idle',
    lastSyncedAt: null,
    localVersion: 0,
    serverVersion: 0,
    pendingChanges: 0,
    error: null,
  })
  const [isOnline, setIsOnline] = useState(true)

  // Refs
  const clientRef = useRef<ComplianceClient | null>(null)
  const syncManagerRef = useRef<StateSyncManager | null>(null)

  // Initialize client
  if (!clientRef.current) {
    clientRef.current = new ComplianceClient({
      apiEndpoint,
      apiKey,
      tenantId,
      onError: err => {
        setError(err)
        onError?.(err)
      },
    })
  }

  const client = clientRef.current

  // Modules
  const dsgvo = useMemo(
    () => createDSGVOModule(client, () => state),
    [client, state]
  )
  const compliance = useMemo(
    () => createComplianceModule(client, () => state),
    [client, state]
  )
  const rag = useMemo(() => createRAGModule(client), [client])
  const security = useMemo(
    () => createSecurityModule(client, () => state),
    [client, state]
  )

  // Initialize sync manager
  useEffect(() => {
    if (enableBackendSync && typeof window !== 'undefined') {
      syncManagerRef.current = createStateSyncManager(
        client,
        tenantId,
        { debounceMs: 2000, maxRetries: 3 },
        {
          onSyncStart: () => {
            setSyncState(prev => ({ ...prev, status: 'syncing' }))
          },
          onSyncComplete: syncedState => {
            setSyncState(prev => ({
              ...prev,
              status: 'idle',
              lastSyncedAt: new Date(),
              pendingChanges: 0,
            }))
            if (new Date(syncedState.lastModified) > new Date(state.lastModified)) {
              dispatch({ type: 'SET_STATE', payload: syncedState })
            }
          },
          onSyncError: err => {
            setSyncState(prev => ({
              ...prev,
              status: 'error',
              error: err.message,
            }))
            setError(err)
          },
          onConflict: () => {
            setSyncState(prev => ({ ...prev, status: 'conflict' }))
          },
          onOffline: () => {
            setIsOnline(false)
            setSyncState(prev => ({ ...prev, status: 'offline' }))
          },
          onOnline: () => {
            setIsOnline(true)
            setSyncState(prev => ({ ...prev, status: 'idle' }))
          },
        }
      )
    }

    return () => {
      syncManagerRef.current?.destroy()
    }
  }, [enableBackendSync, tenantId, client])

  // Load initial state
  useEffect(() => {
    const loadInitialState = async () => {
      setIsLoading(true)
      try {
        // Load from localStorage first
        if (typeof window !== 'undefined') {
          const stored = localStorage.getItem(`${SDK_STORAGE_KEY}-${tenantId}`)
          if (stored) {
            const parsed = JSON.parse(stored)
            if (parsed.lastModified) {
              parsed.lastModified = new Date(parsed.lastModified)
            }
            dispatch({ type: 'SET_STATE', payload: parsed })
          }
        }

        // Then load from server if enabled
        if (enableBackendSync && syncManagerRef.current) {
          const serverState = await syncManagerRef.current.loadFromServer()
          if (serverState) {
            dispatch({ type: 'SET_STATE', payload: serverState })
          }
        }
      } catch (err) {
        setError(err as Error)
        onError?.(err as Error)
      } finally {
        setIsLoading(false)
        setIsInitialized(true)
      }
    }

    loadInitialState()
  }, [tenantId, enableBackendSync])

  // Auto-save
  useEffect(() => {
    if (!isInitialized || !state.preferences.autoSave) return

    const saveTimeout = setTimeout(() => {
      try {
        if (typeof window !== 'undefined') {
          localStorage.setItem(`${SDK_STORAGE_KEY}-${tenantId}`, JSON.stringify(state))
        }

        if (enableBackendSync && syncManagerRef.current) {
          syncManagerRef.current.queueSync(state)
        }
      } catch (err) {
        console.error('Failed to save state:', err)
      }
    }, 1000)

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

  // Keyboard shortcuts
  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 })
        onNavigate?.(step.url)
      }
    },
    [onNavigate]
  )

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

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

  const canGoNext = useMemo(() => getNextStep(state.currentStep) !== undefined, [state.currentStep])
  const canGoPrevious = useMemo(
    () => getPreviousStep(state.currentStep) !== undefined,
    [state.currentStep]
  )

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

  // Checkpoints
  const validateCheckpoint = useCallback(
    async (checkpointId: string): Promise<CheckpointStatus> => {
      if (enableBackendSync) {
        try {
          const result = await client.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 through to local validation
        }
      }

      // Local validation
      const status: CheckpointStatus = {
        checkpointId,
        passed: true,
        validatedAt: new Date(),
        validatedBy: 'SYSTEM',
        errors: [],
        warnings: [],
      }

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

  const overrideCheckpoint = useCallback(
    async (checkpointId: string, reason: string): Promise<void> => {
      const existingStatus = state.checkpoints[checkpointId]
      const overriddenStatus: CheckpointStatus = {
        ...existingStatus,
        checkpointId,
        passed: true,
        overrideReason: reason,
        overriddenBy: state.userId,
        overriddenAt: new Date(),
        errors: [],
        warnings: existingStatus?.warnings || [],
      }

      dispatch({ type: 'SET_CHECKPOINT_STATUS', payload: { id: checkpointId, status: overriddenStatus } })
    },
    [state.checkpoints, state.userId]
  )

  const getCheckpointStatus = useCallback(
    (checkpointId: string): CheckpointStatus | undefined => {
      return state.checkpoints[checkpointId]
    },
    [state.checkpoints]
  )

  // State Updates
  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 } })
  }, [])

  // Persistence
  const saveState = useCallback(async (): Promise<void> => {
    try {
      if (typeof window !== 'undefined') {
        localStorage.setItem(`${SDK_STORAGE_KEY}-${tenantId}`, JSON.stringify(state))
      }

      if (enableBackendSync && syncManagerRef.current) {
        await syncManagerRef.current.forceSync(state)
      }
    } catch (err) {
      setError(err as Error)
      throw err
    }
  }, [state, tenantId, enableBackendSync])

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

      if (typeof window !== 'undefined') {
        const stored = localStorage.getItem(`${SDK_STORAGE_KEY}-${tenantId}`)
        if (stored) {
          dispatch({ type: 'SET_STATE', payload: JSON.parse(stored) })
        }
      }
    } catch (err) {
      setError(err as Error)
      throw err
    } finally {
      setIsLoading(false)
    }
  }, [tenantId, enableBackendSync])

  const resetState = useCallback(() => {
    dispatch({ type: 'RESET_STATE' })
    if (typeof window !== 'undefined') {
      localStorage.removeItem(`${SDK_STORAGE_KEY}-${tenantId}`)
    }
  }, [tenantId])

  // Sync
  const forceSyncToServer = useCallback(async (): Promise<void> => {
    if (enableBackendSync && syncManagerRef.current) {
      await syncManagerRef.current.forceSync(state)
    }
  }, [state, enableBackendSync])

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

  const value: ComplianceContextValue = {
    state,
    dispatch,
    client,
    dsgvo,
    compliance,
    rag,
    security,
    currentStep,
    goToStep,
    goToNextStep,
    goToPreviousStep,
    canGoNext,
    canGoPrevious,
    completionPercentage,
    phase1Completion,
    phase2Completion,
    validateCheckpoint,
    overrideCheckpoint,
    getCheckpointStatus,
    updateUseCase,
    addRisk,
    updateControl,
    saveState,
    loadState,
    resetState,
    syncState,
    forceSyncToServer,
    isOnline,
    exportState,
    isCommandBarOpen,
    setCommandBarOpen,
    isInitialized,
    isLoading,
    error,
  }

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