'use client'

import {
  createContext,
  useContext,
  useReducer,
  useCallback,
  ReactNode,
} from 'react'
import {
  AOIResponse,
  AOITheme,
  AOIQuality,
  Difficulty,
  GeoJSONPolygon,
  LearningNode,
  GeoLernweltState,
} from '@/app/geo-lernwelt/types'

// Initial state
const initialState: GeoLernweltState = {
  currentAOI: null,
  drawnPolygon: null,
  selectedTheme: 'topographie',
  quality: 'medium',
  difficulty: 'mittel',
  learningNodes: [],
  selectedNode: null,
  isDrawing: false,
  isLoading: false,
  error: null,
  unityReady: false,
  unityProgress: 0,
}

// Action types
type GeoAction =
  | { type: 'SET_AOI'; payload: AOIResponse | null }
  | { type: 'SET_POLYGON'; payload: GeoJSONPolygon | null }
  | { type: 'SET_THEME'; payload: AOITheme }
  | { type: 'SET_QUALITY'; payload: AOIQuality }
  | { type: 'SET_DIFFICULTY'; payload: Difficulty }
  | { type: 'SET_LEARNING_NODES'; payload: LearningNode[] }
  | { type: 'ADD_LEARNING_NODE'; payload: LearningNode }
  | { type: 'UPDATE_LEARNING_NODE'; payload: LearningNode }
  | { type: 'REMOVE_LEARNING_NODE'; payload: string }
  | { type: 'SELECT_NODE'; payload: LearningNode | null }
  | { type: 'SET_DRAWING'; payload: boolean }
  | { type: 'SET_LOADING'; payload: boolean }
  | { type: 'SET_ERROR'; payload: string | null }
  | { type: 'SET_UNITY_READY'; payload: boolean }
  | { type: 'SET_UNITY_PROGRESS'; payload: number }
  | { type: 'RESET' }

// Reducer
function geoReducer(state: GeoLernweltState, action: GeoAction): GeoLernweltState {
  switch (action.type) {
    case 'SET_AOI':
      return { ...state, currentAOI: action.payload }

    case 'SET_POLYGON':
      return { ...state, drawnPolygon: action.payload }

    case 'SET_THEME':
      return { ...state, selectedTheme: action.payload }

    case 'SET_QUALITY':
      return { ...state, quality: action.payload }

    case 'SET_DIFFICULTY':
      return { ...state, difficulty: action.payload }

    case 'SET_LEARNING_NODES':
      return { ...state, learningNodes: action.payload }

    case 'ADD_LEARNING_NODE':
      return {
        ...state,
        learningNodes: [...state.learningNodes, action.payload],
      }

    case 'UPDATE_LEARNING_NODE':
      return {
        ...state,
        learningNodes: state.learningNodes.map((node) =>
          node.id === action.payload.id ? action.payload : node
        ),
      }

    case 'REMOVE_LEARNING_NODE':
      return {
        ...state,
        learningNodes: state.learningNodes.filter(
          (node) => node.id !== action.payload
        ),
        selectedNode:
          state.selectedNode?.id === action.payload ? null : state.selectedNode,
      }

    case 'SELECT_NODE':
      return { ...state, selectedNode: action.payload }

    case 'SET_DRAWING':
      return { ...state, isDrawing: action.payload }

    case 'SET_LOADING':
      return { ...state, isLoading: action.payload }

    case 'SET_ERROR':
      return { ...state, error: action.payload }

    case 'SET_UNITY_READY':
      return { ...state, unityReady: action.payload }

    case 'SET_UNITY_PROGRESS':
      return { ...state, unityProgress: action.payload }

    case 'RESET':
      return initialState

    default:
      return state
  }
}

// Context types
interface GeoContextValue {
  state: GeoLernweltState
  dispatch: React.Dispatch<GeoAction>
  // Convenience actions
  setAOI: (aoi: AOIResponse | null) => void
  setPolygon: (polygon: GeoJSONPolygon | null) => void
  setTheme: (theme: AOITheme) => void
  setQuality: (quality: AOIQuality) => void
  setDifficulty: (difficulty: Difficulty) => void
  setLearningNodes: (nodes: LearningNode[]) => void
  addNode: (node: LearningNode) => void
  updateNode: (node: LearningNode) => void
  removeNode: (nodeId: string) => void
  selectNode: (node: LearningNode | null) => void
  setDrawing: (drawing: boolean) => void
  setLoading: (loading: boolean) => void
  setError: (error: string | null) => void
  setUnityReady: (ready: boolean) => void
  setUnityProgress: (progress: number) => void
  reset: () => void
}

// Create context
const GeoContext = createContext<GeoContextValue | null>(null)

// Provider component
export function GeoProvider({ children }: { children: ReactNode }) {
  const [state, dispatch] = useReducer(geoReducer, initialState)

  // Convenience action creators
  const setAOI = useCallback(
    (aoi: AOIResponse | null) => dispatch({ type: 'SET_AOI', payload: aoi }),
    []
  )

  const setPolygon = useCallback(
    (polygon: GeoJSONPolygon | null) =>
      dispatch({ type: 'SET_POLYGON', payload: polygon }),
    []
  )

  const setTheme = useCallback(
    (theme: AOITheme) => dispatch({ type: 'SET_THEME', payload: theme }),
    []
  )

  const setQuality = useCallback(
    (quality: AOIQuality) => dispatch({ type: 'SET_QUALITY', payload: quality }),
    []
  )

  const setDifficulty = useCallback(
    (difficulty: Difficulty) =>
      dispatch({ type: 'SET_DIFFICULTY', payload: difficulty }),
    []
  )

  const setLearningNodes = useCallback(
    (nodes: LearningNode[]) =>
      dispatch({ type: 'SET_LEARNING_NODES', payload: nodes }),
    []
  )

  const addNode = useCallback(
    (node: LearningNode) => dispatch({ type: 'ADD_LEARNING_NODE', payload: node }),
    []
  )

  const updateNode = useCallback(
    (node: LearningNode) =>
      dispatch({ type: 'UPDATE_LEARNING_NODE', payload: node }),
    []
  )

  const removeNode = useCallback(
    (nodeId: string) =>
      dispatch({ type: 'REMOVE_LEARNING_NODE', payload: nodeId }),
    []
  )

  const selectNode = useCallback(
    (node: LearningNode | null) => dispatch({ type: 'SELECT_NODE', payload: node }),
    []
  )

  const setDrawing = useCallback(
    (drawing: boolean) => dispatch({ type: 'SET_DRAWING', payload: drawing }),
    []
  )

  const setLoading = useCallback(
    (loading: boolean) => dispatch({ type: 'SET_LOADING', payload: loading }),
    []
  )

  const setError = useCallback(
    (error: string | null) => dispatch({ type: 'SET_ERROR', payload: error }),
    []
  )

  const setUnityReady = useCallback(
    (ready: boolean) => dispatch({ type: 'SET_UNITY_READY', payload: ready }),
    []
  )

  const setUnityProgress = useCallback(
    (progress: number) => dispatch({ type: 'SET_UNITY_PROGRESS', payload: progress }),
    []
  )

  const reset = useCallback(() => dispatch({ type: 'RESET' }), [])

  const value: GeoContextValue = {
    state,
    dispatch,
    setAOI,
    setPolygon,
    setTheme,
    setQuality,
    setDifficulty,
    setLearningNodes,
    addNode,
    updateNode,
    removeNode,
    selectNode,
    setDrawing,
    setLoading,
    setError,
    setUnityReady,
    setUnityProgress,
    reset,
  }

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

// Hook to use context
export function useGeo() {
  const context = useContext(GeoContext)
  if (!context) {
    throw new Error('useGeo must be used within a GeoProvider')
  }
  return context
}

// Hook for just the state (read-only)
export function useGeoState() {
  const { state } = useGeo()
  return state
}
