import React, { useState } from "react";
import * as config from "../config";
import jwt_decode from "jwt-decode";
import { ToastContainer } from "react-toastify";

interface Auth {
  accessToken: string | null;
  refreshToken: string | null;
  setValue: (a: Omit<Auth, "setValue" | "checkJWTSession">) => void;
  checkJWTSession: () => boolean;
}

const defaultValue: Omit<Auth, "setValue" | "checkJWTSession"> = {
  accessToken: localStorage.getItem(config.ACCESS_TOKEN_LOCAL_STORAGE_KEY),
  refreshToken: localStorage.getItem(config.REFRESH_TOKEN_LOCAL_STORAGE_KEY),
};

export const Context = React.createContext<Auth>(defaultValue as Auth);

export default function Provider(props: any) {
  let value: Auth;
  let setValue: (f: (a: Auth) => Auth) => void;
  // eslint-disable-next-line prefer-const
  [value, setValue] = useState<Auth>({
    ...defaultValue,
    // Returns:
    // TRUE => still valid
    // FALSE => invalid
    checkJWTSession: () => {
      try {
        // Check if JWT is empty
        if (value.accessToken == null || value.accessToken.length < 3) {
          console.warn("JWT -- Access Token not present!");
          return false;
        } else {
          // Check if JWT is not expired
          const decoded: { sub: string; exp: number; iat: number } = jwt_decode(
            value.accessToken!,
          );
          const d = new Date(0);
          d.setUTCSeconds(decoded.exp);
          if (new Date() > d) {
            console.warn("JWT -- Access Token expired!");
            return false;
          } else {
            return true;
          }
        }
      } catch (e) {
        console.error(e);
        return false;
      }
    },
    setValue: (newState: Omit<Auth, "setValue" | "checkJWTSession">) =>
      setValue((currentState) => {
        if (newState.accessToken) {
          localStorage.setItem(
            config.ACCESS_TOKEN_LOCAL_STORAGE_KEY as string,
            newState.accessToken,
          );
          value.accessToken = newState.accessToken;
        }

        if (newState.accessToken === null) {
          localStorage.removeItem(
            config.ACCESS_TOKEN_LOCAL_STORAGE_KEY as string,
          );
        }

        if (newState.refreshToken) {
          localStorage.setItem(
            config.REFRESH_TOKEN_LOCAL_STORAGE_KEY as string,
            newState.refreshToken,
          );
          value.refreshToken = newState.refreshToken;
        }

        if (newState.refreshToken === null) {
          localStorage.removeItem(
            config.REFRESH_TOKEN_LOCAL_STORAGE_KEY as string,
          );
        }

        return { ...currentState, ...newState };
      }),
  });

  return (
    <Context.Provider value={value}>
      {props.children}
      <ToastContainer />
    </Context.Provider>
  );
}
