/*
 * @Author: thy
 * @Date: 2023-11-08 09:28:17
 * @LastEditors: thy
 * @LastEditTime: 2023-11-17 09:36:01
 * @Description: file content
 * @FilePath: \dsk-operate-ui\src\utils\iframeTools.js
 */

import { dskAccessToken } from '@/api/common';
import { getUrlSearchQuery, isUrl, paramsToQuery } from "@/utils/";
import { Message } from "element-ui";


/**
 * iframe嵌入参数处理
 */
class IframeTools {
  queryParams = {};
  pluginDomain = "";
  subSystemIframe = null;
  refreshTimer = null;
  count = 0;
  authToken = "";
  origin = location.origin;
  isOuter = false;
  /**
   * 插件域名地址
   * @param {string} pluginDomain 默认当前环境变量VUE_APP_SUB_SYSTEM_ADDRESS
   * @param {HTMLIFrameElement} subSystemIframe 子系统iframe dom节点
   * @returns
   */
  constructor(subSystemIframe, pluginDomain = process.env.VUE_APP_SUB_SYSTEM_ADDRESS) {
    try {
      const query = getUrlSearchQuery();
      if (!query.url) return Message.warning("缺少子系统目标地址");
      // 传入的iframeUrl不是一个合法地址
      if (!isUrl(pluginDomain)) return Message.warning("子系统源地址不合法");
      // 未获取到子系统节点
      if (!subSystemIframe) return Message.warning("未获取到子系统节点");
      this.queryParams = query;
      this.pluginDomain = pluginDomain;
      this.subSystemIframe = subSystemIframe;
      this.isOuter = query.isOuter && typeof JSON.parse(query.isOuter) == "boolean" ? JSON.parse(query.isOuter) : false;
      // 是一个合法地址 初始化 先替换域名地址 再获取令牌并 拼接
      this.init();
    } catch (error) {
      throw new Error(error);
    }
  }

  /**
   * 初始化类
   */
  async init() {
    try {
      // 不是合法url的情况下需要拼接完整路径 例如path /xxxx/xxx
      !isUrl(this.queryParams.url) ? this.queryParams.url = `${this.pluginDomain}${this.queryParams.url}` : null;
      // 获取到子系统加载地址query参数
      const subSystemParams = getUrlSearchQuery(this.queryParams.url);
      // 获取子系统path
      const subSystemUrl = new URL(this.queryParams.url);
      // 以环境文件地址为准 拼接子系统查询参数
      let url = this.isOuter ? this.queryParams.url : `${this.pluginDomain}${subSystemUrl.pathname == "/" ? "" : subSystemUrl.pathname}`;
      // 子系统地址带有查询参数 处理
      Object.keys(subSystemParams).length ? url = `${url}?${paramsToQuery(subSystemParams)}` : null;
      // 获取授权 token
      const { accessToken, expire } = await this.getSubSystemToken();
      // 拼接授权地址
      if (accessToken) {
        this.authToken = accessToken;
        const query = {
          initTime: new Date().valueOf(),
          ak: accessToken,
          uid: accessToken,
          origin: this.origin
        };
        url = `${url}${paramsToQuery(query) ? "?" + paramsToQuery(query) : ""}`;
        this.queryParams.url = url;
        console.log(this.queryParams.url);
        // 倒计时刷新token 正常误差10s 提前获取
        this.setTokenRefresh(expire * 1000 - 1000 * 10);
      }
    } catch (error) {
      console.log(error);
      Message.warning(error.message ? error.message : (typeof error == "string") ? error : "子系统初始化错误");
    }
  }

  /**
   * 获取子系统token
   */
  async getSubSystemToken() {
    try {
      const result = await dskAccessToken();
      if (result.code == 200) {
        return result.data;
      }
      throw new Error("子系统获取授权失败");
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据服务端返回过期时间刷新token有效期
   */
  setTokenRefresh(expire) {
    if (!expire) throw new Error("令牌无有效的刷新时间");
    return new Promise((resolve, reject) => {
      // 只允许出现一个定时器实例状态
      this.clearRefreshTimer();
      this.refreshTimer = setTimeout(async () => {
        const result = await this.getSubSystemToken();
        if (result.accessToken) {
          this.count = 0;
          this.authToken = result.accessToken;
          this.setTokenRefresh(result.expire);
          resolve(result);
        } else {
          // 请求失败进行重试 清理定时器
          this.clearRefreshTimer();
          // 尝试最多3次刷新 重新调取接口
          while (this.count < 3) {
            // 重试次数大于等于三次 停止刷新
            if (this.count >= 3) {
              return reject("子系统令牌刷新失败,请稍后重试");
            }
            this.count++;
            Message.warning(`授权失败，正在尝试第 ${this.count} 次刷新令牌，请勿进行操作`);
            const refreshAuth = await this.getSubSystemToken();
            if (refreshAuth.accessToken) {
              this.count = 0;
              this.authToken = refreshAuth.accessToken;
              this.setTokenRefresh(refreshAuth.expire);
              resolve(refreshAuth);
            }
          }
        }
      }, expire);
    });
  }

  clearRefreshTimer() {
    clearTimeout(this.refreshTimer);
    this.refreshTimer = null;
  }

}

export default IframeTools;