// Note: Based on https://usehooks.com/useAuth/


import React, { useState, useContext, createContext, ReactFragment } from "react";
import PersonIcon from '@material-ui/icons/Person';
import * as serverApi from '../api';

export interface AuthUser {
    id: number,
    email: string,
    icon: ReactFragment,
}

export interface Auth {
    user: AuthUser | null,
    signout: () => void,
    signin: (email: string, password: string) => Promise<AuthUser>,
    signup: (email: string, password: string) => Promise<void>,
};

const authContext = createContext<Auth>({
    user: null,
    signout: () => { },
    signin: (email: string, password: string) => {
        throw new Error("Auth object not initialized.");
    },
    signup: (email: string, password: string) => {
        throw new Error("Auth object not initialized.");
    },
});

export function ProvideAuth(props: { children: any }) {
    const auth = useProvideAuth();
    return <authContext.Provider value={auth}>{props.children}</authContext.Provider>;
}

export const useAuth = () => {
    return useContext(authContext);
};

function persistAuth(auth: AuthUser | null) {
    let s = window.sessionStorage;

    if(auth === null) {
        s.removeItem('userId');
        s.removeItem('userEmail');
        return;
    }

    s.setItem('userId', auth.id.toString());
    s.setItem('userEmail', auth.email);
    // TODO icon
}

function loadAuth(): AuthUser | null {
    let s = window.sessionStorage;
    let id = s.getItem('userId');
    let email = s.getItem('userEmail');

    if (id && email) {
        return {
            id: parseInt(id),
            email: email,
            icon: <PersonIcon />
        }
    }
    return null;
}

function useProvideAuth() {
    const [user, setUser] = useState<AuthUser | null>(loadAuth());

    // TODO: password maybe shouldn't be encoded into the URL.
    const signin = (email: string, password: string) => {
        return (async () => {
            const urlBase = (process.env.REACT_APP_BACKEND || "") + serverApi.LoginEndpoint;
            const url = `${urlBase}?username=${encodeURIComponent(email)}&password=${encodeURIComponent(password)}`;

            const response = await fetch(url, { method: "POST" });
            const json = await response.json();
            if (!("userId" in json)) {
                throw new Error("No UserID received from login.");
            }

            const user = {
                id: json.userId,
                email: email,
                icon: <PersonIcon />,
            }
            setUser(user);
            persistAuth(user);
            return user;
        })();
    };

    const signup = (email: string, password: string) => {
        return (async () => {
            const requestOpts = {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    email: email,
                    password: password,
                })
            };

            const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.RegisterUserEndpoint, requestOpts)
            if (!response.ok) {
                throw new Error("Failed to register user.")
            }
        })();
    };

    const signout = () => {
        console.log("Signing out.");
        setUser(null);
        persistAuth(null);
        return (async () => {
            const url = (process.env.REACT_APP_BACKEND || "") + serverApi.LogoutEndpoint;
            const response = await fetch(url, { method: "POST" });
            if (!response.ok) {
                throw new Error("Failed to log out.");
            }
        })();
    };

    // Return the user object and auth methods
    return {
        user,
        signin,
        signup,
        signout,
    };
}