import { useQuery } from '@tanstack/react-query'
import React, { ReactNode, useEffect } from 'react'
import { Platform } from 'react-native'
import { Constants } from '@/constants/Constants'
import { useAuth } from '@/hooks/useAuth'
import { useSetLocationAccuracy } from '@/hooks/useGame'
import { useGeolocationMutation } from '@/hooks/mutations/useGeolocationMutation'
import { useQueuedLocations, useSetLastPlayerLocation, useSetLastPlayerLocations, useUnqueueLocation } from '@/hooks/useLocation'
import { isAuthValid } from '@/utils/features/auth/authSlice'
import { PlayerLocation } from '@/utils/features/location/locationSlice'
import { useStartGeolocationServiceEffect } from '@/utils/geolocation'
import * as SecureStore from '@/utils/SecureStore'
import { socket } from '@/utils/socket'
import { Accuracy } from 'expo-location'

export default function GeolocationProvider({ children }: { children: ReactNode }) {
  useStartGeolocationServiceEffect()

  const auth = useAuth()
  const setLocationAccuracy = useSetLocationAccuracy()
  const geolocationsQueue = useQueuedLocations()
  const unqueueLocation = useUnqueueLocation()
  const setLastPlayerLocations = useSetLastPlayerLocations()
  const setLastPlayerLocation = useSetLastPlayerLocation()
  const geolocationMutation = useGeolocationMutation({
    auth,
    onPostSuccess: (data, variables) => unqueueLocation(variables),
    onError: ({ response, error }) => console.error(response, error),
  })

  useEffect(() => {
    SecureStore.getItemAsync('locationAccuracy').then(locationAccuracyString => {
      if (!locationAccuracyString)
        setLocationAccuracy(Accuracy.Balanced)
      else if (locationAccuracyString === 'null')
        setLocationAccuracy(null)
      else
        setLocationAccuracy(+locationAccuracyString)
    })
  }, [])
  
  if (Platform.OS !== "web") {
    useEffect(() => {
      if (geolocationsQueue.length === 0 || geolocationMutation.isPending || !isAuthValid(auth))
        return
        const locToSend = geolocationsQueue[0]
        geolocationMutation.mutate(locToSend)
    }, [auth, geolocationMutation.status, geolocationsQueue])
  }

  const lastLocationsQuery = useQuery({
    queryKey: ['get-last-locations', auth.token],
    queryFn: () => fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/geolocations/last-locations/`, {
      method: "GET",
      headers: {
        "Authorization": `Bearer ${auth.token}`,
        "Content-Type": "application/json",
      },
    }).then(resp => resp.json()),
    initialData: [],
    enabled: isAuthValid(auth),
    refetchInterval: Constants.QUERY_REFETCH_INTERVAL * 1000,
  })
  useEffect(() => {
    if (lastLocationsQuery.isSuccess && lastLocationsQuery.data)
      setLastPlayerLocations(lastLocationsQuery.data)
  }, [lastLocationsQuery.status, lastLocationsQuery.dataUpdatedAt])

  useEffect(() => {
    const locationListener = async (data: PlayerLocation) => {
      if (data.playerId)
        setLastPlayerLocation(data)
    }
    socket.on('last-location', locationListener)
    return () => { socket.off('last-location', locationListener) }
  }, [])

  return <>
    {children}
  </>
}