"use client"

import React, { createContext, useContext, useReducer, useEffect, useCallback } from 'react'
import { 
  DeviceRegistrationSession, 
  RegistrationStatus, 
  DeviceDto, 
  InitiateRegistrationRequest,
  WebSocketDeviceEvent
} from '../types/device'
import { devicesApi } from '../services/devices'
import { deviceWebSocketService, WebSocketEventHandlers } from '../services/websocket'
import { useAuth } from './auth-context'

// State interface
interface DeviceRegistrationState {
  currentSession: DeviceRegistrationSession | null
  registeredDevices: DeviceDto[]
  isLoading: boolean
  error: string | null
  wsConnected: boolean
  qrCodeUrl: string | null
}

// Action types
type DeviceRegistrationAction =
  | { type: 'SET_LOADING'; payload: boolean }
  | { type: 'SET_ERROR'; payload: string | null }
  | { type: 'SET_CURRENT_SESSION'; payload: DeviceRegistrationSession | null }
  | { type: 'SET_REGISTERED_DEVICES'; payload: DeviceDto[] }
  | { type: 'ADD_DEVICE'; payload: DeviceDto }
  | { type: 'UPDATE_DEVICE'; payload: DeviceDto }
  | { type: 'REMOVE_DEVICE'; payload: string }
  | { type: 'SET_WS_CONNECTED'; payload: boolean }
  | { type: 'SET_QR_CODE_URL'; payload: string | null }
  | { type: 'UPDATE_SESSION_STATUS'; payload: RegistrationStatus }
  | { type: 'RESET_STATE' }

// Initial state
const initialState: DeviceRegistrationState = {
  currentSession: null,
  registeredDevices: [],
  isLoading: false,
  error: null,
  wsConnected: false,
  qrCodeUrl: null,
}

// Reducer
function deviceRegistrationReducer(
  state: DeviceRegistrationState,
  action: DeviceRegistrationAction
): DeviceRegistrationState {
  switch (action.type) {
    case 'SET_LOADING':
      return { ...state, isLoading: action.payload }
    
    case 'SET_ERROR':
      return { ...state, error: action.payload, isLoading: false }
    
    case 'SET_CURRENT_SESSION':
      return { ...state, currentSession: action.payload }
    
    case 'SET_REGISTERED_DEVICES':
      return { ...state, registeredDevices: action.payload }
    
    case 'ADD_DEVICE':
      return { 
        ...state, 
        registeredDevices: [...state.registeredDevices, action.payload] 
      }
    
    case 'UPDATE_DEVICE':
      return {
        ...state,
        registeredDevices: state.registeredDevices.map(device =>
          device.id === action.payload.id ? action.payload : device
        )
      }
    
    case 'REMOVE_DEVICE':
      return {
        ...state,
        registeredDevices: state.registeredDevices.filter(
          device => device.id !== action.payload
        )
      }
    
    case 'SET_WS_CONNECTED':
      return { ...state, wsConnected: action.payload }
    
    case 'SET_QR_CODE_URL':
      return { ...state, qrCodeUrl: action.payload }
    
    case 'UPDATE_SESSION_STATUS':
      return {
        ...state,
        currentSession: state.currentSession 
          ? { ...state.currentSession, status: action.payload }
          : null
      }
    
    case 'RESET_STATE':
      return initialState
    
    default:
      return state
  }
}

// Context interface
interface DeviceRegistrationContextType {
  state: DeviceRegistrationState
  
  // Registration actions
  initiateRegistration: (request: InitiateRegistrationRequest) => Promise<void>
  cancelRegistration: () => Promise<void>
  refreshSession: () => Promise<void>
  
  // Device management actions
  refreshDevices: () => Promise<void>
  updateDevice: (deviceId: string, updates: Partial<DeviceDto>) => Promise<void>
  deleteDevice: (deviceId: string) => Promise<void>
  
  // WebSocket actions
  connectWebSocket: () => Promise<void>
  disconnectWebSocket: () => void
  
  // Utility actions
  clearError: () => void
  resetState: () => void
}

const DeviceRegistrationContext = createContext<DeviceRegistrationContextType | undefined>(undefined)

// Provider component
interface DeviceRegistrationProviderProps {
  children: React.ReactNode
}

export function DeviceRegistrationProvider({ children }: DeviceRegistrationProviderProps) {
  const [state, dispatch] = useReducer(deviceRegistrationReducer, initialState)
  const { user, isAuthenticated } = useAuth()

  // WebSocket event handlers
  const wsEventHandlers: WebSocketEventHandlers = {
    onConnect: () => {
      dispatch({ type: 'SET_WS_CONNECTED', payload: true })
    },
    
    onDisconnect: () => {
      dispatch({ type: 'SET_WS_CONNECTED', payload: false })
    },
    
    onError: (error) => {
      console.error('WebSocket error:', error)
      dispatch({ type: 'SET_ERROR', payload: error.message })
    },
    
    onDeviceConnected: (data) => {
      if (state.currentSession && data.sessionId === state.currentSession.id) {
        dispatch({ type: 'UPDATE_SESSION_STATUS', payload: RegistrationStatus.DEVICE_CONNECTED })
      }
    },
    
    onRegistrationCompleted: (data) => {
      if (state.currentSession && data.sessionId === state.currentSession.id) {
        dispatch({ type: 'UPDATE_SESSION_STATUS', payload: RegistrationStatus.COMPLETED })
        
        // Add the new device to the list
        if (data.device) {
          dispatch({ type: 'ADD_DEVICE', payload: data.device })
        }
        
        // Clear current session after a delay
        setTimeout(() => {
          dispatch({ type: 'SET_CURRENT_SESSION', payload: null })
          dispatch({ type: 'SET_QR_CODE_URL', payload: null })
        }, 2000)
      }
    },
    
    onRegistrationFailed: (data) => {
      if (state.currentSession && data.sessionId === state.currentSession.id) {
        dispatch({ type: 'UPDATE_SESSION_STATUS', payload: RegistrationStatus.FAILED })
        dispatch({ type: 'SET_ERROR', payload: data.error || 'Registration failed' })
      }
    },
    
    onDeviceStatusChanged: (data) => {
      // Update device status in the list
      dispatch({ type: 'UPDATE_DEVICE', payload: data.device })
    },
  }

  // Initialize WebSocket event handlers
  useEffect(() => {
    deviceWebSocketService.setEventHandlers(wsEventHandlers)
  }, [state.currentSession?.id])

  // Connect WebSocket when authenticated
  useEffect(() => {
    if (isAuthenticated && !state.wsConnected) {
      connectWebSocket()
    } else if (!isAuthenticated && state.wsConnected) {
      disconnectWebSocket()
    }
  }, [isAuthenticated])

  // Load devices on mount when authenticated
  useEffect(() => {
    if (isAuthenticated) {
      refreshDevices()
    }
  }, [isAuthenticated])

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      disconnectWebSocket()
    }
  }, [])

  // Actions implementation
  const initiateRegistration = useCallback(async (request: InitiateRegistrationRequest) => {
    dispatch({ type: 'SET_LOADING', payload: true })
    dispatch({ type: 'SET_ERROR', payload: null })
    
    try {
      const response = await devicesApi.initiateRegistration(request)
      
      // Transform the response into a session object
      const session: DeviceRegistrationSession = {
        id: response.claim_id,
        userProfileId: user?.id || '',
        registrationCode: response.claim_token,
        pinCode: response.fallback_pin,
        status: RegistrationStatus.WAITING_FOR_DEVICE,
        expiresAt: response.expires_at,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      }
      
      dispatch({ type: 'SET_CURRENT_SESSION', payload: session })
      dispatch({ type: 'SET_QR_CODE_URL', payload: response.qr_code_url })
      
      // Join the registration session room
      if (state.wsConnected) {
        deviceWebSocketService.joinRegistrationSession(response.claim_id)
      }
      
    } catch (error) {
      dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Failed to initiate registration' })
    } finally {
      dispatch({ type: 'SET_LOADING', payload: false })
    }
  }, [state.wsConnected, user?.id])

  const cancelRegistration = useCallback(async () => {
    if (!state.currentSession) return
    
    dispatch({ type: 'SET_LOADING', payload: true })
    
    try {
      await devicesApi.cancelRegistration(state.currentSession.id)
      
      // Leave the registration session room
      if (state.wsConnected) {
        deviceWebSocketService.leaveRegistrationSession(state.currentSession.id)
      }
      
      dispatch({ type: 'SET_CURRENT_SESSION', payload: null })
      dispatch({ type: 'SET_QR_CODE_URL', payload: null })
      
    } catch (error) {
      dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Failed to cancel registration' })
    } finally {
      dispatch({ type: 'SET_LOADING', payload: false })
    }
  }, [state.currentSession?.id, state.wsConnected])

  const refreshSession = useCallback(async () => {
    if (!state.currentSession) return
    
    try {
      const session = await devicesApi.getRegistrationSession(state.currentSession.id)
      dispatch({ type: 'SET_CURRENT_SESSION', payload: session })
    } catch (error) {
      dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Failed to refresh session' })
    }
  }, [state.currentSession?.id])

  const refreshDevices = useCallback(async () => {
    if (!isAuthenticated) return
    
    try {
      const response = await devicesApi.getDevices()
      dispatch({ type: 'SET_REGISTERED_DEVICES', payload: response.devices })
    } catch (error) {
      dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Failed to load devices' })
    }
  }, [isAuthenticated])

  const updateDevice = useCallback(async (deviceId: string, updates: Partial<DeviceDto>) => {
    dispatch({ type: 'SET_LOADING', payload: true })
    
    try {
      const updatedDevice = await devicesApi.updateDevice(deviceId, updates)
      dispatch({ type: 'UPDATE_DEVICE', payload: updatedDevice })
    } catch (error) {
      dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Failed to update device' })
    } finally {
      dispatch({ type: 'SET_LOADING', payload: false })
    }
  }, [])

  const deleteDevice = useCallback(async (deviceId: string) => {
    dispatch({ type: 'SET_LOADING', payload: true })
    
    try {
      await devicesApi.deleteDevice(deviceId)
      dispatch({ type: 'REMOVE_DEVICE', payload: deviceId })
    } catch (error) {
      dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Failed to delete device' })
    } finally {
      dispatch({ type: 'SET_LOADING', payload: false })
    }
  }, [])

  const connectWebSocket = useCallback(async () => {
    try {
      const token = localStorage.getItem('accessToken')
      if (!token) throw new Error('No authentication token')
      
      await deviceWebSocketService.connect(token)
    } catch (error) {
      dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Failed to connect to real-time updates' })
    }
  }, [])

  const disconnectWebSocket = useCallback(() => {
    deviceWebSocketService.disconnect()
    dispatch({ type: 'SET_WS_CONNECTED', payload: false })
  }, [])

  const clearError = useCallback(() => {
    dispatch({ type: 'SET_ERROR', payload: null })
  }, [])

  const resetState = useCallback(() => {
    dispatch({ type: 'RESET_STATE' })
  }, [])

  const contextValue: DeviceRegistrationContextType = {
    state,
    initiateRegistration,
    cancelRegistration,
    refreshSession,
    refreshDevices,
    updateDevice,
    deleteDevice,
    connectWebSocket,
    disconnectWebSocket,
    clearError,
    resetState,
  }

  return (
    <DeviceRegistrationContext.Provider value={contextValue}>
      {children}
    </DeviceRegistrationContext.Provider>
  )
}

// Hook for using the context
export function useDeviceRegistration() {
  const context = useContext(DeviceRegistrationContext)
  if (context === undefined) {
    throw new Error('useDeviceRegistration must be used within a DeviceRegistrationProvider')
  }
  return context
}