import React from 'react'
import { SDKState } from './types'
import { SDKApiClient, getSDKApiClient, resetSDKApiClient } from './api-client'
import { StateSyncManager, createStateSyncManager, SyncState, SyncCallbacks } from './sync'
import { ExtendedSDKAction } from './context-types'

// =============================================================================
// SYNC CALLBACK BUILDER
// =============================================================================

/**
 * Builds the SyncCallbacks object used by the StateSyncManager.
 * Keeps the provider component cleaner by extracting this factory.
 */
export function buildSyncCallbacks(
  setSyncState: React.Dispatch<React.SetStateAction<SyncState>>,
  setIsOnline: React.Dispatch<React.SetStateAction<boolean>>,
  dispatch: React.Dispatch<ExtendedSDKAction>,
  stateRef: React.MutableRefObject<SDKState>
): SyncCallbacks {
  return {
    onSyncStart: () => {
      setSyncState(prev => ({ ...prev, status: 'syncing' }))
    },
    onSyncComplete: (syncedState) => {
      setSyncState(prev => ({
        ...prev,
        status: 'idle',
        lastSyncedAt: new Date(),
        pendingChanges: 0,
      }))
      if (syncedState.lastModified > stateRef.current.lastModified) {
        dispatch({ type: 'SET_STATE', payload: syncedState })
      }
    },
    onSyncError: (error) => {
      setSyncState(prev => ({
        ...prev,
        status: 'error',
        error: error.message,
      }))
    },
    onConflict: () => {
      setSyncState(prev => ({ ...prev, status: 'conflict' }))
    },
    onOffline: () => {
      setIsOnline(false)
      setSyncState(prev => ({ ...prev, status: 'offline' }))
    },
    onOnline: () => {
      setIsOnline(true)
      setSyncState(prev => ({ ...prev, status: 'idle' }))
    },
  }
}

// =============================================================================
// INITIAL STATE LOADER
// =============================================================================

/**
 * Loads SDK state from localStorage and optionally from the server,
 * dispatching SET_STATE as appropriate.
 */
export async function loadInitialState(params: {
  storageKey: string
  enableBackendSync: boolean
  projectId?: string
  syncManager: StateSyncManager | null
  apiClient: SDKApiClient | null
  dispatch: React.Dispatch<ExtendedSDKAction>
}): Promise<void> {
  const { storageKey, enableBackendSync, projectId, syncManager, apiClient, dispatch } = params

  // First, try loading from localStorage
  const stored = localStorage.getItem(storageKey)
  if (stored) {
    const parsed = JSON.parse(stored)
    if (parsed.lastModified) {
      parsed.lastModified = new Date(parsed.lastModified)
    }
    dispatch({ type: 'SET_STATE', payload: parsed })
  }

  // Then, try loading from server if backend sync is enabled
  if (enableBackendSync && syncManager) {
    const serverState = await syncManager.loadFromServer()
    if (serverState) {
      const localTime = stored ? new Date(JSON.parse(stored).lastModified).getTime() : 0
      const serverTime = new Date(serverState.lastModified).getTime()
      if (serverTime > localTime) {
        dispatch({ type: 'SET_STATE', payload: serverState })
      }
    }
  }

  // Load project metadata (name, status, etc.) from backend
  if (enableBackendSync && projectId && apiClient) {
    try {
      const info = await apiClient.getProject(projectId)
      dispatch({ type: 'SET_STATE', payload: { projectInfo: info } })
    } catch (err) {
      console.warn('Failed to load project info:', err)
    }
  }
}

// =============================================================================
// INIT / CLEANUP HELPERS
// =============================================================================

export function initSyncInfra(
  enableBackendSync: boolean,
  tenantId: string,
  projectId: string | undefined,
  apiClientRef: React.MutableRefObject<SDKApiClient | null>,
  syncManagerRef: React.MutableRefObject<StateSyncManager | null>,
  callbacks: SyncCallbacks
): void {
  if (!enableBackendSync || typeof window === 'undefined') return

  apiClientRef.current = getSDKApiClient(tenantId, projectId)
  syncManagerRef.current = createStateSyncManager(
    apiClientRef.current,
    tenantId,
    { debounceMs: 2000, maxRetries: 3 },
    callbacks,
    projectId
  )
}

export function cleanupSyncInfra(
  enableBackendSync: boolean,
  syncManagerRef: React.MutableRefObject<StateSyncManager | null>,
  apiClientRef: React.MutableRefObject<SDKApiClient | null>
): void {
  if (syncManagerRef.current) {
    syncManagerRef.current.destroy()
    syncManagerRef.current = null
  }
  if (enableBackendSync) {
    resetSDKApiClient()
    apiClientRef.current = null
  }
}
