import * as appService from "../services/login";
import { routerRedux } from "dva/router";
import { initFilter } from "../utils/common";
import storage from "../utils/storage";
import { history as globalHistory } from "../utils/history";
import { cloneDeep } from "lodash";
import ReactDOM from "react-dom";
import { Spin } from "antd";
import config from "../config";

function recurseMenu(menus, parentMenu = {}, flatMenus = []) {
  menus.forEach((menu) => {
    const { Node: Menu, Children: ChildMenus } = menu;
    menu.Menu = Menu;
    menu.ChildMenus = ChildMenus;
    Menu.idLevels = (parentMenu.idLevels || []).concat(Menu.ID);
    Menu.nameLevels = (parentMenu.nameLevels || []).concat(Menu.NAME);
    Menu.menuLevels = (parentMenu.menuLevels || []).concat(Menu.MENU_LEVEL);
    Menu.childMenuLevels = (parentMenu.childMenuLevels || []).concat([
      ChildMenus,
    ]);
    flatMenus.push(Menu);
    ChildMenus && ChildMenus.length && recurseMenu(ChildMenus, Menu, flatMenus);
  });
}

// 当前正在请求的数量
let requestCount = 0;

// 显示loading
function showLoading() {
  const spinStyle = {
    position: "fixed",
    width: "100vw",
    height: "100vh",
    justifyContent: "center",
    alignItems: "center",
    display: "flex",
    top: 0,
    left: 0,
    background: "rgba(229, 229, 229, 0.5)",
    zIndex: 1000,
  };
  if (requestCount === 0) {
    var dom = document.createElement("div");
    dom.setAttribute("id", "loading");
    document.body.appendChild(dom);
    ReactDOM.render(
      <div style={spinStyle}>
        <Spin tip="加载中..." size="large" />
      </div>,
      dom
    );
  }
  requestCount++;
}

// 隐藏loading
function hideLoading() {
  requestCount--;
  if (requestCount === 0) {
    document.body.removeChild(document.getElementById("loading"));
  }
}

export default {
  namespace: "login",
  state: {
    loginInfo: {},
    OrgId: "",
    baseConfig: {},
    userId: "",
    user: {},
    Tenant: storage("lacal").getItem("Tenant").val,
    Notifications: [],
    screenLocked: false, // 是否锁屏
    flatMenus: [],
    currActivatedTab: null, // 用于面包屑导航，同步于 model app
    currActivatedMenu: null, // 当前选中的菜单项，同步于 model app
  },
  subscriptions: {
    setup({ dispatch, history }) {
      history.listen((params) => {
        const toLogin = function () {
          let tm;
          showLoading();
          tm = setTimeout(() => {
            localStorage.removeItem("accessToken");
            dispatch(routerRedux.push("/login"));
            hideLoading();
          }, 10000);
          const { username, password } =
            storage("lacal").getItem("loginUserVerify").val;
          const webOrgId = storage("lacal").getItem("webOrgId").val;
          dispatch({
            type: "toLogin",
            payload: {
              Parameter1: username,
              Parameter2: password,
              Parameter4: webOrgId,
              Parameter5: storage("lacal").getItem("formConfigVersion").val,
              Parameter7: true,
            },
          }).then((validRes) => {
            if (validRes) {
              dispatch({
                type: "getOrg",
                payload: {
                  Sort: "CODE",
                  Order: 0,
                  Parameter10: window.location.host,
                  Parameter11: "0",
                },
              });
              dispatch({
                type: "refreshToken",
              });
              dispatch({
                type: "app/getCurrVer",
              });
              dispatch({
                type: "app/getAllEnum",
              }).then((e) => {
                clearTimeout(tm);
                hideLoading();
              });
            }
          });
        };

        const { pathname } = params;
        if (pathname !== "/login") {
          /**
           * 当前页不在登录页，并且 local 不存在 token
           * 那么直接跳转登录页
           */
          if (!storage("lacal").getItem("accessToken").val) {
            dispatch(routerRedux.push("/login"));
            return;
          }
          /**
           * 当前页不在登录页，并且 local 存在 token
           * 如果不存在 OrgId，则说明还未登录，此时调用登录接口
           */
          dispatch({
            type: "checkLoginStatus",
            onFail: () => toLogin(),
          });
        } else {
          /**
           * 当前页在登录页，并且 local 存在 token
           * 则直接跳转到首页，首页调用的接口会验证此 token 是否过期
           * 如果 local token 真的过期，那么还是会自动跳转到登录页
           * 如果 local token 没过期，则正常停留在主页
           */
          if (storage("lacal").getItem("accessToken").val) {
            if (window.navigator.userAgent.indexOf("Windows") < 1) {
              window.location.replace(config.guideH5Host);
              // dispatch(routerRedux.push("/HomeMobileNew"));
            } else {
              dispatch(routerRedux.push("/home"));
            }
            // 新开 tab 页面，直接从 login 路径进来，则需要重新检查一下是否登录，未登录则执行登录获取到菜单以及必要数据
            dispatch({
              type: "checkLoginStatus",
              onFail: () => toLogin(),
            });
          }
        }
      });
    },
  },
  effects: {
    // 获取组织列表
    *getOrg({ payload }, { call, put }) {
      const ret = yield call(appService.getOrg, payload);
      if (ret) {
        const { Tenant = "", Data = [] } = ret;
        storage("lacal").setItem("Tenant", Tenant);
        storage("lacal").setItem("RootOrgId", Data[0]?.Node?.ID || "");
        yield put({ type: "save", payload: { Tenant } });
      }
      return ret;
    },
    // 获取 Token
    *getToken({ payload }, { call }) {
      return yield call(appService.getToken, payload);
    },
    // 刷新 Token，以保持登录状态
    *refreshToken({ payload }, { call, put, select }) {
      // 锁屏状态下不更新
      const { screenLocked } = yield select((state) => state.login);
      if (screenLocked) return;
      // 存在 payload 则只更新 payload 中的 token
      if (payload) {
        const { access_token, refreshToken, expiresIn } = payload;
        storage("lacal").setItem("accessToken", access_token);
        storage("lacal").setItem("refreshToken", refreshToken);
        storage("lacal").setItem("expiresIn", expiresIn);
        storage("lacal").setItem("refreshTimestamp", new Date().getTime());
        return;
      }
      // 如果刷新的时候已经是过期之后的时间了，则不再继续刷新 token
      const nowTimestamp = new Date().getTime();
      const refreshTimestamp = storage("lacal").getItem("refreshTimestamp").val;
      const expiresIn = storage("lacal").getItem("expiresIn").val;
      // 登陆过期
      if (
        refreshTimestamp &&
        refreshTimestamp + expiresIn * 1000 <= nowTimestamp
      ) {
        console.log("过期了");
        localStorage.removeItem("accessToken");
        globalHistory.push({ pathname: "/login" });
        return;
      }
      // 接口刷新 token
      const RefreshToken = storage("lacal").getItem("refreshToken").val;
      const ret = yield call(appService.getToken, {
        RefreshToken,
        grant_type: 2,
      });
      if (ret && !ret.error) {
        const { access_token, refreshToken, expiresIn } = ret;
        storage("lacal").setItem("accessToken", access_token);
        storage("lacal").setItem("refreshToken", refreshToken);
        storage("lacal").setItem("expiresIn", expiresIn);
        storage("lacal").setItem("refreshTimestamp", new Date().getTime());
      }
    },
    // 登录、获取信息
    *toLogin({ payload, loginPayload }, { call, put, select }) {
      const ret = yield call(appService.getLoginInfo, payload);
      if (ret) {
        if (loginPayload) {
          const {
            accessToken,
            refreshToken,
            expiresIn,
            username,
            password,
            userid,
          } = loginPayload;
          storage("lacal").setItem("accessToken", accessToken); // access_token存入localStorage
          storage("lacal").setItem("refreshToken", refreshToken);
          storage("lacal").setItem("expiresIn", expiresIn);
          storage("lacal").setItem("refreshTimestamp", new Date().getTime());
          storage("lacal").setItem("userid", userid);
          storage("lacal").setItem("loginUserVerify", { username, password }); // 登录凭证存入localStorage
        }
        storage("lacal").setItem("webOrgId", ret.User.ORG_ID);
        storage("lacal").setItem("DataRule", ret.DataRule || []);
        storage("lacal").setItem("OrgRule", ret.OrgRule || []);
        storage("lacal").setItem("departmentId", ret.User.DEPARTMENT_ID);
        storage("lacal").setItem("UserType", ret.UserType);
        const localStorage = window.localStorage;

        ret.FormConfigVersion &&
          storage("lacal").setItem("formConfigVersion", ret.FormConfigVersion);
        // 拍平 Menus
        const flatMenus = [];
        const copyMenus = cloneDeep(ret.Menus);
        recurseMenu(copyMenus, undefined, flatMenus);
        ret.Menus = copyMenus;
        // 存储 model state
        yield put({
          type: "save",
          payload: {
            loginInfo: ret,
            OrgId: ret.User.ORG_ID,
            OrgCode: ret.User.Nav_Org ? ret.User.Nav_Org.CODE : "",
            baseConfig: ret.BaseConfig,
            userType: ret.UserType,
            roles: ret.Roles,
            rolePerm: ret.Nav_RolePerm,
            userId: ret.User.ID,
            user: ret.User,
            flatMenus,
          },
        });
        // 不是很清楚为什么这里要清除这个 requestKey
        // const localStorage = window.localStorage
        if (localStorage) {
          for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            if (key.indexOf("_requestKey") > -1) {
              localStorage.removeItem(key);
            }
          }
        }
        // 获取消息提醒
        const getNoticesParams = initFilter(
          ret.User.ORG_ID,
          "",
          "CREATE_TIME",
          1,
          1,
          ret.User.ID
        );
        yield put({ type: "getNotices", payload: getNoticesParams });
      }
      return ret;
    },
    // 验证登录状态
    *checkLoginStatus({ onSuccess, onFail }, { select }) {
      const { OrgId } = yield select((state) => state.login);
      if (!OrgId) {
        onFail instanceof Function && onFail();
      } else {
        onSuccess instanceof Function && onSuccess();
      }
    },
    // 获取消息通知
    *getNotices({ payload }, { call, put }) {
      const ret = yield call(appService.getNotices, payload);
      yield put({
        type: "save",
        payload: {
          Notifications: ret,
        },
      });
      return ret;
    },
    // 获取告警日志
    *getAlarmLog({ payload }, { call }) {
      return yield call(appService.getAlarmLog, payload);
    },
    // 修改密码
    *modifyPassword({ payload }, { call }) {
      return yield call(appService.modifyPassword, payload);
    },
  },
  reducers: {
    save(state, action) {
      return { ...state, ...action.payload };
    },
  },
};
