import { createContext, ReactNode, useEffect, useReducer } from 'react';
// utils
import axios from '../utils/axios';
// import { isValidToken, setSession } from '../utils/jwt';
import { setSession, getSession, getUser } from '../utils/token';
// @types
import { ActionMap, AuthState, AuthUser, JWTContextType } from '../@types/auth';
// ----------------------------------------------------------------------
import { Navigate, useLocation } from 'react-router-dom';

enum Types {
  Initial = 'INITIALIZE',
  Login = 'LOGIN',
  Logout = 'LOGOUT',
  Register = 'REGISTER',
}

type JWTAuthPayload = {
  [Types.Initial]: {
    isAuthenticated: boolean;
    user: AuthUser;
  };
  [Types.Login]: {
    user: AuthUser;
  };
  [Types.Logout]: undefined;
  [Types.Register]: {
    user: AuthUser;
  };
};

export type JWTActions = ActionMap<JWTAuthPayload>[keyof ActionMap<JWTAuthPayload>];

const initialState: AuthState = {
  isAuthenticated: false,
  isInitialized: false,
  user: null,
};

const JWTReducer = (state: AuthState, action: JWTActions) => {
  switch (action.type) {
    case 'INITIALIZE':
      return {
        isAuthenticated: action.payload.isAuthenticated,
        isInitialized: true,
        user: action.payload.user,
      };
    case 'LOGIN':
      return {
        ...state,
        isAuthenticated: true,
        user: action.payload.user,
      };
    case 'LOGOUT':
      return {
        ...state,
        isAuthenticated: false,
        user: null,
      };

    case 'REGISTER':
      return {
        ...state,
        isAuthenticated: true,
        user: action.payload.user,
      };

    default:
      return state;
  }
};

const AuthContext = createContext<JWTContextType | null>(null);

// ----------------------------------------------------------------------

type AuthProviderProps = {
  children: ReactNode;
};

function AuthProvider({ children }: AuthProviderProps) {
  const [state, dispatch] = useReducer(JWTReducer, initialState);
  let location = useLocation();
  const accessToken = getSession();

  useEffect(() => {
    (async () => {
      try {
        // const accessToken = getSession();

        if (accessToken) {
          setSession(accessToken);

          const response = await axios.get('/user');
          const user = response.data;

          dispatch({
            type: Types.Initial,
            payload: {
              isAuthenticated: true,
              user,
            },
          });
        } else {
          dispatch({
            type: Types.Initial,
            payload: {
              isAuthenticated: false,
              user: null,
            },
          });
        }
      } catch (err) {
        dispatch({
          type: Types.Initial,
          payload: {
            isAuthenticated: false,
            user: null,
          },
        });
      }
    })();
  }, [accessToken]);

  
  const login = async (email: string, password: string) => axios
        .post('/login', { email, password })
        .then((response) => {
          const { user, token } = response.data;
          setSession(token);

          dispatch({
            type: Types.Login,
            payload: {
              user,
            }
          });
        })
        .catch(error => {
          if (error.response.status !== 404) throw error.response
          if (error.response.status !== 422) throw error.response
        });

  const register = async (email: string, password: string, firstName: string, lastName: string) => {
    const response = await axios.post('/api/register', {
      email,
      password,
      firstName,
      lastName,
    });
    const { accessToken, user } = response.data;

    window.localStorage.setItem('accessToken', accessToken);
    dispatch({
      type: Types.Register,
      payload: {
        user,
      },
    });
  };

  const logout = async () => {
    setSession(null);
    dispatch({ type: Types.Logout });
  };

  return (<AuthContext.Provider
      value={{
        ...state,
        method: 'jwt',
        login,
        logout,
        register,
      }}
    >
      {children}
    </AuthContext.Provider>
  );

  // if (state.isInitialized) {
  // return (!state.isAuthenticated && location.pathname !== '/auth/login') ? 
  //   (<Navigate to="/auth/login" replace={true} />)
  // : false && location.pathname == '/auth/login' ? 
  //     (<Navigate to="/dashboard" replace={true} />)
  //   : (
  //     <AuthContext.Provider
  //       value={{
  //         ...state,
  //         method: 'jwt',
  //         login,
  //         logout,
  //         register,
  //       }}
  //     >
  //       {children}
  //     </AuthContext.Provider>
  //   );
  // } else {
  //   return (<Navigate to="/auth/login" replace={true} />)
  // }
}

export { AuthContext, AuthProvider };
