'use client'

/**
 * Side-effect hooks extracted from ComplianceProvider.
 *
 * Each function encapsulates one useEffect concern so provider.tsx
 * stays under 300 LOC.
 */

import { useEffect, RefObject } from 'react'
import type { SDKState } from '@breakpilot/compliance-sdk-types'
import {
  ComplianceClient,
  StateSyncManager,
  createStateSyncManager,
} from '@breakpilot/compliance-sdk-core'
import { SDK_STORAGE_KEY } from './provider-context'

// =============================================================================
// TYPES
// =============================================================================

export interface SyncStateSetters {
  setSyncState: React.Dispatch<React.SetStateAction<{
    status: string
    lastSyncedAt: Date | null
    localVersion: number
    serverVersion: number
    pendingChanges: number
    error: string | null
  }>>
  setIsOnline: (v: boolean) => void
  setError: (e: Error | null) => void
  dispatch: React.Dispatch<{ type: string; payload?: unknown }>
}

// =============================================================================
// SYNC MANAGER EFFECT
// =============================================================================

export function useSyncManagerEffect(
  enableBackendSync: boolean,
  tenantId: string,
  client: ComplianceClient,
  state: SDKState,
  syncManagerRef: RefObject<StateSyncManager | null>,
  { setSyncState, setIsOnline, setError, dispatch }: SyncStateSetters
): void {
  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()
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [enableBackendSync, tenantId, client])
}

// =============================================================================
// LOAD INITIAL STATE EFFECT
// =============================================================================

export interface LoadStateSetters {
  setIsLoading: (v: boolean) => void
  setIsInitialized: (v: boolean) => void
  setError: (e: Error | null) => void
  dispatch: React.Dispatch<{ type: string; payload?: unknown }>
  onError?: (e: Error) => void
}

export function useLoadInitialStateEffect(
  tenantId: string,
  enableBackendSync: boolean,
  syncManagerRef: RefObject<StateSyncManager | null>,
  { setIsLoading, setIsInitialized, setError, dispatch, onError }: LoadStateSetters
): void {
  useEffect(() => {
    const loadInitialState = async () => {
      setIsLoading(true)
      try {
        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 })
          }
        }

        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()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [tenantId, enableBackendSync])
}

// =============================================================================
// AUTO-SAVE EFFECT
// =============================================================================

export function useAutoSaveEffect(
  state: SDKState,
  tenantId: string,
  isInitialized: boolean,
  enableBackendSync: boolean,
  syncManagerRef: RefObject<StateSyncManager | null>
): void {
  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 EFFECT
// =============================================================================

export function useKeyboardShortcutsEffect(
  isCommandBarOpen: boolean,
  setCommandBarOpen: (fn: (prev: boolean) => boolean) => void
): void {
  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, setCommandBarOpen])
}
