import { ComponentChildren, createContext, JSX } from 'preact'
import { StateUpdater, useContext, useEffect, useState } from 'preact/hooks'
import { User } from '../../shared/model'
import { prependBaseUrl, server } from '../api'

type UserContextValue = {
    ready: boolean
    user: User | null
    setUser: StateUpdater<User | null>
    refreshUser: () => Promise<User | null>
}

const UserContext = createContext<UserContextValue | null>(null)

type CurrentUserHook = () => [User | null, boolean]

export const useCurrentUser: CurrentUserHook = () => {
    const userContext = useContext(UserContext)
    if (!userContext) {
        return [null, false]
    }

    const { ready, user } = userContext
    return [user, ready]
}

type UserFunctionsHook = () => {
    login: (username: string) => Promise<void>
    logout: () => Promise<void>
}

// TODO: remove login as it is deprecated

export const useUserFunctions: UserFunctionsHook = () => {
    const login = async (username: string) => {
        await fetch(prependBaseUrl(`/api/login`), {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                id: username,
            }),
        })
        await refreshUser()
    }

    const userContext = useContext(UserContext)
    if (!userContext) {
        return { login, logout: async () => {} }
    }

    const { setUser, refreshUser } = userContext

    const logout = async () => {
        await server.post('/api/logout')
        setUser(null)
    }

    return { login, logout }
}

export const UserProvider = ({ children }: { children: ComponentChildren }): JSX.Element => {
    const [ready, setReady] = useState<boolean>(false)
    const [user, setUser] = useState<User | null>(null)

    const refreshUser = async () => {
        const user = await server.get('/api/current-user')
        setUser(user)
        setReady(true)
        return user
    }

    // Fetch user when first mounted
    useEffect(() => {
        refreshUser()
    }, [])

    return <UserContext.Provider value={{ ready, user, setUser, refreshUser }}>{children}</UserContext.Provider>
}
