import { createContext, ReactNode, useEffect, useReducer } from 'react';
// utils
import axios from '../utils/axios';
import { setSession, getSession } from '../utils/token';
// @types
import { ActionMap, AuthState, AuthUser, JWTContextType } from '../@types/auth';

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

enum Types {
  Initial = 'INITIALIZE',
  Login = 'LOGIN',
  ValidateOtp = 'VALIDATE-OTP',
  Logout = 'LOGOUT',
}

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

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: false,
        user: null,
      };
    case 'VALIDATE-OTP':
      return {
        ...state,
        isAuthenticated: true,
        user: action.payload.user,
      };
    case 'LOGOUT':
      return {
        ...state,
        isAuthenticated: false,
        user: null,
      };
    default:
      return state;
  }
};

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

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

type AuthProviderProps = {
  children: ReactNode;
};

function AuthProvider({ children }: AuthProviderProps) {
  const [state, dispatch] = useReducer(JWTReducer, initialState);
  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 (phoneOrEmail: string) =>
    axios
      .post('/login', { phoneOrEmail })
      .then(() => {
        dispatch({
          type: Types.Login,
        });
      })
      .catch((error) => {
        if (error.response.status !== 404) throw error.response;
        if (error.response.status !== 422) throw error.response;
      });

  const validateOtp = async (phoneOrEmail: string, otp: string) =>
    axios
      .post('/verify-code', { phoneOrEmail: phoneOrEmail, otp })
      .then((response) => {
        const { token } = response.data.data;
        setSession(token);

        return response.data;
      })
      .catch((error) => {
        if (error.response.status !== 404) throw error.response;
        if (error.response.status !== 422) throw error.response;
      });

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

  return (
    <AuthContext.Provider
      value={{
        ...state,
        method: 'jwt',
        login,
        validateOtp,
        logout,
      }}
    >
      {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 };
