import { Box } from '@mui/material'
import Container from '@mui/material/Container'
import { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Outlet } from 'react-router-dom'
import { AppBar } from '../components/AppBar/AppBar'
import { restoreState, setAuthState, setMetadataEvent } from '../store/actions'
import {
  clearAuthToken,
  clearState,
  getRoboHashPicture,
  loadState,
  saveNsecBunkerDelegatedKey
} from '../utils'
import { LoadingSpinner } from '../components/LoadingSpinner'
import { Dispatch } from '../store/store'
import { MetadataController, NostrController } from '../controllers'
import { LoginMethods } from '../store/auth/types'
import { setUserRobotImage } from '../store/userRobotImage/action'
import { State } from '../store/rootReducer'
import { Event, kinds } from 'nostr-tools'

export const MainLayout = () => {
  const dispatch: Dispatch = useDispatch()
  const [isLoading, setIsLoading] = useState(true)
  const authState = useSelector((state: State) => state.auth)

  useEffect(() => {
    const metadataController = new MetadataController()

    const logout = () => {
      dispatch(
        setAuthState({
          keyPair: undefined,
          loggedIn: false,
          usersPubkey: undefined,
          loginMethod: undefined,
          nsecBunkerPubkey: undefined
        })
      )

      dispatch(setMetadataEvent(metadataController.getEmptyMetadataEvent()))

      // clear authToken saved in local storage
      clearAuthToken()
      clearState()

      // update nsecBunker delegated key
      const newDelegatedKey =
        NostrController.getInstance().generateDelegatedKey()
      saveNsecBunkerDelegatedKey(newDelegatedKey)
    }

    const restoredState = loadState()
    if (restoredState) {
      dispatch(restoreState(restoredState))

      const { loggedIn, loginMethod, usersPubkey, nsecBunkerRelays } =
        restoredState.auth

      if (loggedIn) {
        if (!loginMethod || !usersPubkey) return logout()

        if (loginMethod === LoginMethods.nsecBunker) {
          if (!nsecBunkerRelays) return logout()

          const nostrController = NostrController.getInstance()
          nostrController.nsecBunkerInit(nsecBunkerRelays).then(() => {
            nostrController.createNsecBunkerSigner(usersPubkey)
          })
        }

        const handleMetadataEvent = (event: Event) => {
          dispatch(setMetadataEvent(event))
        }

        metadataController.on(usersPubkey, (kind: number, event: Event) => {
          if (kind === kinds.Metadata) {
            handleMetadataEvent(event)
          }
        })

        metadataController.findMetadata(usersPubkey).then((metadataEvent) => {
          if (metadataEvent) handleMetadataEvent(metadataEvent)
        })
      }
    }

    setIsLoading(false)
  }, [dispatch])

  /**
   * When authState change user logged in / or app reloaded
   * we set robohash avatar in the global state based on user npub
   * so that avatar will be consistent across the app when kind 0 is empty
   */
  useEffect(() => {
    if (authState && authState.loggedIn) {
      const pubkey = authState.usersPubkey || authState.keyPair?.public

      if (pubkey) {
        dispatch(setUserRobotImage(getRoboHashPicture(pubkey)))
      }
    }
  }, [authState])

  if (isLoading) return <LoadingSpinner desc="Loading App" />

  return (
    <>
      <AppBar />

      <Box className="main">
        <Container
          sx={{
            position: 'relative',
            maxWidth: {
              xs: '550px'
            }
          }}
        >
          <Outlet />
        </Container>
      </Box>
    </>
  )
}
