import { CoreConst, OrgData } from '@ibiz-template/core';
import { ModelUtil } from '@ibiz-template/model';
import { getCookie, setCookie } from 'qx-util';
import { UnauthorizedHandler } from '../unauthorized-handler/unauthorized-handler';
import { PluginFactory } from '@/plugin';

/**
 * 刷新token定时器id
 *
 * @author: zhujiamin
 * @Date: 2023-12-15 11:27:16
 */
let refreshTokenTimeId: NodeJS.Timeout | undefined;

/**
 * 预加载应用级引用插件
 *
 * @description 临时解决方式
 * @author chitanda
 * @date 2022-10-31 16:10:57
 * @return {*}  {Promise<void>}
 */
async function loadAppPlugins(): Promise<void> {
  const modelService = await ModelUtil.getModelService();
  const { app } = modelService;
  const pluginRefs = app.getAllPSAppPFPluginRefs();
  const map = new Map();
  const plugin = ibiz.plugin as PluginFactory;
  const all = pluginRefs?.map(async pluginRef => {
    if (
      pluginRef &&
      pluginRef.runtimeObject &&
      pluginRef.rTObjectName &&
      pluginRef.rTObjectRepo
    ) {
      const { rTObjectName, rTObjectRepo } = pluginRef;
      if (
        plugin.appPlugins.indexOf(rTObjectRepo) !== -1 &&
        map.has(rTObjectRepo) !== true
      ) {
        map.set(rTObjectRepo, true);
        await ibiz.plugin.loadPluginRef(rTObjectName, rTObjectRepo);
      }
    }
  });
  if (all) {
    await Promise.all(all);
  }
}

/**
 * 初始化应用配置参数
 *
 * @export
 * @param {IData} userParam
 * @return {*}  {Promise<void>}
 */
export async function initConfig(userParam: IData): Promise<void> {
  if (userParam) {
    Object.keys(userParam).forEach(key => {
      const value = ibiz.util.rawValue.format(userParam[key]);
      const keys = key.split('.');
      let currentObj = ibiz.config as IData;
      for (let i = 0; i < keys.length; i++) {
        const k = keys[i];
        if (i === keys.length - 1) {
          currentObj[k] = value;
        } else {
          currentObj[k] = currentObj[k] || {};
          currentObj = currentObj[k];
        }
      }
    });
  }
}

/**
 * 初始化模型
 *
 * @author chitanda
 * @date 2022-07-20 20:07:58
 * @return {*}  {Promise<void>}
 */
async function loadModel(): Promise<void> {
  await ModelUtil.create(async modelPath => {
    const url = `${ibiz.env.remoteModelUrl}${modelPath}`;
    const res = await ibiz.net.get(url);
    if (res.ok) {
      const userParam = res.data.getUserParam || {};
      await initConfig(userParam);
      return res.data as IModel;
    }
    return {};
  });
  await loadAppPlugins();
}

/**
 * 加载应用数据
 *
 * @author chitanda
 * @date 2022-07-20 20:07:50
 * @return {*}  {Promise<void>}
 */
async function loadAppData(): Promise<void> {
  const res = await ibiz.net.get('/appdata');
  if (res.ok) {
    ibiz.appData = res.data;
  }
}

/**
 * 加载组织数据
 *
 * @author chitanda
 * @date 2022-07-20 20:07:44
 * @return {*}  {Promise<void>}
 */
async function loadOrgData(): Promise<void> {
  const res = await ibiz.net.get(`/uaa/getbydcsystem/${ibiz.env.dcSystem}`);
  if (res.ok) {
    const orgDataItems = res.data as OrgData[];
    if (orgDataItems) {
      const [data] = orgDataItems;
      ibiz.orgData = data;
    }
  }
}

/**
 * 设置token刷新定时器
 *
 * @author lxm
 * @date 2023-02-13 09:09:23
 */
function setRefreshToken() {
  // 清除之前的定时器
  if (refreshTokenTimeId) {
    clearTimeout(refreshTokenTimeId);
  }
  const token = getCookie(CoreConst.TOKEN);
  const expirein = getCookie(CoreConst.TOKEN_EXPIRES);
  if (token && expirein) {
    // 计算到过期时间所需的延时毫秒数，预留提前量
    let wait = Number(expirein) - new Date().getTime();
    const early = 5 * 60 * 1000;
    wait = wait > early ? wait - early : 0;
    refreshTokenTimeId = setTimeout(async () => {
      const res = await ibiz.net.get(`/uaa/refreshtoken2`);
      if (res.ok) {
        setCookie(CoreConst.TOKEN, res.data.token, 0, true);
        const expiredDate =
          new Date().getTime() + (res.data.expirein || 7199) * 1000;
        setCookie(CoreConst.TOKEN_EXPIRES, `${expiredDate}`, 0, true);
      }
      // 下一次延时做准备
      setRefreshToken();
    }, wait);
  }
}

/**
 * 加载应用模型全局样式
 *
 * @author chitanda
 * @date 2023-07-24 20:07:41
 * @protected
 * @return {*}  {Promise<void>}
 */
async function loadAppModelStyle(): Promise<void> {
  await ibiz.net
    .get(`${ibiz.env.remoteModelUrl}/PSSYSAPP.json.css`)
    .then(res => {
      const dom = document.createElement('style');
      dom.setAttribute('type', 'text/css');
      if (res.request && res.request.responseURL) {
        const url = new URL(res.request.responseURL);
        dom.id = url.pathname;
      }
      dom.innerHTML = res.data as unknown as string;
      document.head.appendChild(dom);
    })
    .catch(err => {
      ibiz.log.error(`应用模型全局样式加载失败：${err.message}`);
    });
}

/**
 * 应用参数初始化
 *
 * @author chitanda
 * @date 2022-07-20 19:07:54
 * @return {*}  {Promise<void>}
 */
async function appInit(): Promise<void> {
  try {
    await loadOrgData();
    await loadAppData();
    await loadModel();
    setRefreshToken();
    await loadAppModelStyle();
    // 设置权限服务需要的appData里的数据
    await ibiz.authority.init();
    // TODO临时 多应用适配时需要修改 资源路径计算，资源路径上下文计算工具类
    await ibiz.resourcePathUtil.init();
  } catch (error) {
    const { response } = error as IData;
    if (response?.status === 401) {
      await UnauthorizedHandler.handle();
    } else {
      ibiz.log.error(error);
    }
  }
}

/**
 * 应用权限守卫
 *
 * @author chitanda
 * @date 2022-10-28 10:10:29
 * @export
 * @return {*}  {Promise<boolean>}
 */
export async function AuthGuard(): Promise<boolean> {
  await appInit();
  return true;
}
