import { createContext, FC, ReactNode, useMemo, useState, useContext, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import PropTypes from 'prop-types';
import axios from 'axios';
import { IUserProps } from '../common/data/userDummyData';
import { TSignInWOPasswordForm, TSignUpForm } from '../type/auth-form-type';
import { Apis } from '../constants/Apis';
import { TUser } from '../type/user-type';

export interface AuthPropsOld {
	user: string;
	setUser?(...args: unknown[]): unknown;
	userData: Partial<IUserProps>;
}

interface IAuthContextProps  {
  token: string | null;
  userData: TUser | null,
  username: string | null,
  menu: string | null,
  user: string;
	setUser?(...args: unknown[]): unknown;
  authState?: {token: string | null; isAuthenticated: boolean| null};
  setUserData?(...args: unknown[]): unknown;
  setUsername?: (payload: string) => void;
  setMenu?: (payload: string) => void;
  setUserObj?: (payload: string) => void;
  onRegister?: (payload: TSignUpForm) => Promise<any>;
  onLogin?: (payload: TSignInWOPasswordForm) => Promise<any>;
  onLogout?: () => void;
}

const TOKEN_KEY = 'jwt-token';
const USER_OBJ = 'userdata';
const USERNAME = 'username';
const MENU = 'menu';

const AuthContext = createContext<IAuthContextProps>({} as IAuthContextProps);

// This hook can be used to access the user info.
export const useAuth = () => {
  return useContext(AuthContext);
}

interface IAuthContextProviderProps {
	children: ReactNode;
}

export const AuthContextProvider: FC<IAuthContextProviderProps> = ({ children }) => {

  const navigate = useNavigate();

  const [user, setUser] = useState<string>(localStorage.getItem('facit_authUsername') || '');

	// @ts-ignore
  const getToken =  localStorage.getItem(TOKEN_KEY) ? localStorage.getItem(TOKEN_KEY) || '' : null
  const getUserData =  localStorage.getItem(USER_OBJ) ? JSON.parse(localStorage.getItem(USER_OBJ) || '{}') : null
  const getUsername =  localStorage.getItem(USERNAME) ? localStorage.getItem(USERNAME) || '' : null
  const getMenu =  localStorage.getItem(USERNAME) ? localStorage.getItem(MENU) || '' : null

  const [userData, setUserData] = useState(getUserData)
  const [ token, setToken ] = useState( getToken || '')
  const [username, setUsername] = useState<string | null>(getUsername);
  const [menu, setMenu] = useState<string | null>(getMenu);
  
	const [authState, setAuthState] = useState<{token: string | null; isAuthenticated: boolean | null;}>({
    token: token,
    isAuthenticated: false
  });

	
  const setTheUsername = (username: string) => {
    // 1.a set Username state
    setUsername(username);

    // 2.b Store the username in the local storage
    localStorage.setItem(USERNAME, username);
  };

  const setTheMenu = (menu: string) => {
    // 1.a set Menu state
    setMenu(menu);

    // 2.b Store the menu in the local storage
    localStorage.setItem(MENU, menu);
  };

  const setTheUserObj = (user: string) => {
    // 1. set User state
    setUserData(user)

    // 2. Store the user object in the local storage
    localStorage.setItem(USER_OBJ, user);
  };

	const register = async (payload: TSignUpForm) => {
    try {

      const regresult = await axios.post(`${Apis.DATABASE_API_URL}/auth/registerWithoutPassword`, payload)
      console.log(regresult.data)
      if (regresult.data.success){

        // 1. Set User obj
				setUserData(regresult.data.data.user);

        // 1.b Store the user obj in the local storage
				localStorage.setItem(USER_OBJ, JSON.stringify(regresult.data.data.user));

        // 2.a set token
        setToken(regresult.data.data.token_data.access_token);

				// 2.b Store the token in the local storage
				localStorage.setItem(TOKEN_KEY, regresult.data.data.token_data.access_token);

        // 3. Set authstate
        setAuthState({ token: regresult.data.data.token_data.access_token, isAuthenticated: true, });

				// 4. Set the token on the header of all the request to prove that user is authenticated
				axios.defaults.headers.common['Authorization'] = `Bearer ${regresult.data.data.token_data.access_token}`;
			} else {
        // 1. Set User obj
				setUserData(regresult.data.data);

        // 1.b Store the user obj in the local storage
				localStorage.setItem(USER_OBJ, JSON.stringify(regresult.data.data));
      }

      return regresult.data;
    } catch (e) {
      return {error: true, msg: (e as any).response.data.message.text}
    }
  };

  const login = async (payload: TSignInWOPasswordForm) => {
    try {
      
      const result = await axios.post(`${Apis.DATABASE_API_URL}/auth/loginWithoutPassword`, payload);
      console.log(result.data);

			if (result.data.success){

        // 1. Set User obj
				setUserData(result.data.data.user);

        // 1.b Store the user obj in the local storage
				localStorage.setItem(USER_OBJ, JSON.stringify(result.data.data.user));

        // 2.a set token
        setToken(result.data.data.token_data.access_token);

				// 2.b Store the token in the local storage
				localStorage.setItem(TOKEN_KEY, result.data.data.token_data.access_token);

        // 3. Set authstate
        setAuthState({ token: result.data.data.token_data.access_token, isAuthenticated: true, });

				// 4. Set the token on the header of all the request to prove that user is authenticated
				axios.defaults.headers.common['Authorization'] = `Bearer ${result.data.data.token_data.access_token}`;
			}

      return result.data;
    
    } catch (e) {
      console.log(e)
      return {error: true, msg: (e as any).response.data.msg}
    }
  };

  const logout = async () => {

    // 1. Reset User
    setUserData(null);

    // 1.b Delete user obj from storage
    localStorage.removeItem(USER_OBJ);

    // 2.a Reset token
    setToken("");

    // 2.b Delete token from storage
    localStorage.removeItem(TOKEN_KEY);

    // 3 Reset authstate
    setAuthState({ token: null, isAuthenticated: false, });

    // 4. Update HTTP Headers <Route element={<RequireAuth />}>
    axios.defaults.headers.common['Authorization'] = '';

    // 5.a Reset Username
    setUsername('');

    // 5.b Delete username from storage
    localStorage.removeItem(USERNAME);

    // 6.a Reset Menu
    setMenu('');

    // 6.b Delete Menu from storage
    localStorage.removeItem(MENU);

    // 7. Navigate to login page
    navigate(`/auth/sign-in`);

  };

	const value = useMemo(
		() => ({
      token,
      userData,
      username,
      menu,
      user,
      setUser,
			authState,
      setUsername: setTheUsername,
      setMenu: setTheMenu,
      setUserObj: setTheUserObj,
			onRegister: register,
			onLogin: login,
			onLogout: logout,
		}),
		[token, userData],
	);
  

	return <AuthContext.Provider value={value}>
    {children}
  </AuthContext.Provider>;

};

AuthContextProvider.propTypes = {
	children: PropTypes.node.isRequired,
};

export default AuthContext;
