import React, { useReducer, useState } from "react";
import { useContext } from "react";
import { LoaderContext } from "./../loader/LoaderContext";
import { UserContext } from "./userContext";
import {
  getStorageToken,
  isGivenTokenEmpty,
  isGivenTokenExpired,
  isGivenTokenExpiring,
  isGivenTokenInvalid,
} from "../../services/tokenService";

import jwtDecode from "jwt-decode";
import { UserProfile, UserPrivileges } from "../../services/authService";
import {
  getAssignablePermissions,
  transformAssignablePermissions,
} from "../../services/permissionService";

import {
  getHasMultipleBrands,
  getIsSelf,
  getIsPrimaryBrand,
  removeAccessToken,
  removeHasMultipleBrands,
  removeIsPrimaryBrand,
  removeIsSelf,
  getCorpBrandCode,
} from "../../services/localstorageService";
import { getEntityUrl } from "../../services/entityService";
import { dashboardNames, entityNames } from "../../constants/enums";
import { useNavigate } from "react-router-dom";
const baseUserObject = {
  email: "",
  exp: 0,
  role: [],
  iat: 0,
  iss: "",
  jti: "",
  nbf: 0,
  sub: "",
  userProfile: null,
  linkData: null,
  privileges: null,
  distinctModules: [],
};
const reducer = (state, { type, payload }) => {
  switch (type?.toString().toLowerCase()) {
    case "login": {
      let userObject = { ...state.user, ...payload.decode };
      let returned = {
        user: {
          ...userObject,
          isAuthenticated: true,
          userProfile: payload.userProfile,
          linkData: null,
          privileges: payload.privileges,
          role: payload.role,
          distinctModules: payload.distinctModules,
        },
        token: payload.token,
      };

      return returned;
    }
    case "clear":
    case "logout": {
      let userObject = { ...state.user, ...baseUserObject };
      return {
        user: {
          ...userObject,
          isAuthenticated: false,
        },
        token: "",
      };
    }
    default:
      return state;
  }
};

export const UserProvider = ({ children }) => {
  const [waiting, setWaiting] = useState(-1);
  const { updateLoaderStatus } = useContext(LoaderContext);

  const [state, dispatch] = useReducer(reducer, {
    user: baseUserObject,
    token: null,
  });

  const loadScriptsAndStyles = (clientName) => {
    let id = "scriptContainer";
    const container = document.getElementById(id);
    container.innerHTML = "";
    const script = document.createElement("script");
    script.type = "text/babel";
    script.src = `../../styles/${clientName}/js/common.js`;
    script.onload = function () {};
    script.onerror = function () {};
    container.appendChild(script);
  };

  const getProfileAndPrivileges = (
    token,
    hasMultipleBrands,
    isPrimaryBrand,
    isSelf,
    corpBrandCode,
    callbackMethod = null
  ) => {
    updateLoaderStatus(true);
    setWaiting(0);
    const decode = jwtDecode(token);
    UserProfile(decode.email).then(
      (userProfile) => {
        if (userProfile === undefined || userProfile === null) {
          logout();
        } else {
          UserPrivileges(userProfile.id).then(
            (userPrivileges) => {
              getAssignablePermissions(userProfile.brandID).then(
                (data) => {
                  let assignablePermissions =
                    transformAssignablePermissions(data);
                  const set = () => {
                    let role =
                      decode[
                        "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
                      ];

                    let distinctModules = [];
                    for (let c = 0; c < userPrivileges.length; c++) {
                      let privilege = userPrivileges[c];
                      let moduleName = privilege.moduleName;
                      let moduleDescription = privilege.moduleDescription;
                      const existing = distinctModules.find(
                        (x) => x.moduleName === moduleName
                      );
                      if (existing === null || existing === undefined) {
                        distinctModules.push({
                          moduleName: moduleName,
                          moduleDescription: moduleDescription,
                        });
                      }
                    }
                    userProfile.hasMultipleBrands = hasMultipleBrands;
                    userProfile.isPrimaryBrand = isPrimaryBrand;
                    userProfile.isSelf = isSelf;
                    userProfile.corpBrandCode = corpBrandCode;
                    let payload = {
                      distinctModules: distinctModules,
                      role: role,
                      userProfile: userProfile,
                      privileges: userPrivileges,
                      assignablePermissions: assignablePermissions,
                      token: token,
                    };
                    dispatch({ type: "login", payload: payload });
                    loadScriptsAndStyles(userProfile.brandID);
                    if (callbackMethod !== null) {
                      callbackMethod();
                    }
                    updateLoaderStatus(false);
                    setWaiting(1);
                  };
                  set();
                },
                (error) => {
                  updateLoaderStatus(false);
                  setWaiting(1);
                }
              );
            },
            (error) => {
              updateLoaderStatus(false);
              setWaiting(1);
            }
          );
        }
      },
      (error) => {
        updateLoaderStatus(false);
        setWaiting(1);
      }
    );
  };

  const replaceUrl = (dashboard, softReplace = false) => {
    let entityName = null;
    switch (dashboard) {
      case dashboardNames.GROUPS: {
        entityName = entityNames.GROUPMANAGEMENT;
        break;
      }
      case dashboardNames.ROLES: {
        entityName = entityNames.ROLEMANAGEMENT;
        break;
      }
      case dashboardNames.USERS: {
        entityName = entityNames.USERMANAGEMENT;
        break;
      }
      case dashboardNames.HOURSOPERATION: {
        entityName = entityNames.HOURSOPERATION;
        break;
      }
      default: {
        entityName = "";
        break;
      }
    }
    let url = getEntityUrl(entityName);
    if (softReplace === false) {
      window.location.replace(url);
    } else {
      window.history.replaceState(null, "", url);
    }
  };

  const removeAll = () => {
    /*dispatch({ type: "clear", payload: {} });*/
    removeAccessToken();
    /*
    removeHasMultipleBrands();
    removeIsPrimaryBrand();
    removeIsSelf();*/
  };
  const navigate = useNavigate();
  const logout = (redirect = true) => {
    removeAll();
    //dispatch({ type: "logout", payload: {} });
    updateLoaderStatus(false);
    if (redirect === true) {
      navigate("/logout");
    }
  };

  const getTokenDetails = () => {
    let token = getStorageToken();
    let isInValid = false;
    let isExpired = false;
    let isExpiring = false;
    if (
      isGivenTokenInvalid(token) === true ||
      isGivenTokenEmpty(token) === true
    ) {
      isInValid = true;
    } else {
      isExpired = isGivenTokenExpired(token);
      isExpiring = isGivenTokenExpiring(token);
    }
    return {
      token,
      isInValid,
      isExpired,
      isExpiring,
    };
  };

  const getBrandSpecificOptions = () => {
    let hasMultipleBrands = getHasMultipleBrands();
    let isPrimaryBrand = getIsPrimaryBrand();
    let isSelf = getIsSelf();
    let corpBrandCode = getCorpBrandCode();
    return { hasMultipleBrands, isPrimaryBrand, isSelf, corpBrandCode };
  };
  return (
    <UserContext.Provider
      value={{
        state,
        getProfileAndPrivileges,
        removeAll,
        logout,
        waiting,
        getTokenDetails,
        getBrandSpecificOptions,
        replaceUrl,
      }}
    >
      {children}
    </UserContext.Provider>
  );
};
