import React, { useCallback, useEffect } from 'react'
import { io } from 'socket.io-client'

import { Box } from '@chakra-ui/react'
import { Canvas } from 'react-three-fiber'

import MenuOverlay from './MenuOverlay'
import Error from './Error'
import Scene from '../3d'

import useStore, { Transform, UserTransforms } from '../store'
import useLogin from '../hooks/useLogin'
import { Redirect } from 'react-router-dom'

const Museo: React.FC = () => {
  const { response, isLoading } = useLogin<{ authenticated: boolean }>('auth/check')

  const setSocket = useStore((state) => state.setSocket)
  const setError = useStore((state) => state.setError)
  const error = useStore((state) => state.error)
  const setUserTransforms = useStore((state) => state.setUserTransforms)
  const setInitialTransform = useStore((state) => state.setInitialTransform)

  const computeOffsets = useCallback((event) => {
    const { offsetX, offsetY } = event.nativeEvent

    const diffX = window.innerWidth / 2 - offsetX
    const diffY = window.innerHeight / 2 - offsetY

    return {
      offsetX: diffX + offsetX,
      offsetY: diffY + offsetY,
    }
  }, [])

  useEffect(() => {
    if (!response || isLoading) {
      return
    }
    const socket = io()

    const closeSocket = () => {
      setError('SOCKET')
      socket.close()
      setSocket(null)
    }

    setSocket(socket)

    socket.on('disconnect', () => {
      closeSocket()
    })
    socket.on('broadcast-transforms', (payload: UserTransforms) => {
      setUserTransforms(payload)
    })
    socket.on('initial-transform', (payload: Transform | null) => {
      if (payload) {
        setInitialTransform(payload)
      }
    })

    const sendVisitTimeout = setTimeout(() => {
      socket.emit('register-visit')
    }, 15000) // wait 15 to send the event

    return () => {
      closeSocket()
      clearTimeout(sendVisitTimeout)
    }
  }, [response, isLoading])

  if (isLoading || !response) return null

  return response.authenticated === false ? (
    <Redirect to="/" />
  ) : (
    <Box w="100vw" h="100vh">
      {error ? (
        <Error />
      ) : (
        <>
          <MenuOverlay />
          <Canvas
            colorManagement
            concurrent
            gl={{
              antialias: false,
              alpha: false,
            }}
            camera={{
              fov: 45,
              near: 0.25,
              far: 200,
            }}
            raycaster={{ computeOffsets }}
          >
            <Scene />
          </Canvas>
        </>
      )}
    </Box>
  )
}

export default Museo
