import $app from "./app";
import $config from "./config";

const api = {};

// 标志位：控制登录提示弹窗只显示一次
let isLoginPromptShown = false;

// 网络请求封装
const Request = function (opts) {
  const originalComplete = opts.complete;
  return new Promise((resolve, reject) => {
    uni.request(
      Object.assign({}, opts, {
        complete: (res) => {
          const hasSuccess = Boolean(
            res.errMsg == "request:ok" &&
              res.statusCode >= 200 &&
              res.statusCode < 300
          );
          hasSuccess ? resolve(res.data) : reject(res);
          if (originalComplete && typeof originalComplete == "function")
            originalComplete(res);
        },
      })
    );
  });
};

// 路径拼接
const pathJoin = function (...args) {
  return args.join("/").replace(/(?<!:)(\/{2,})/g, "/");
};

// 显示LOADING
const showLoading = function () {
  uni.showLoading({ title: "", mask: true });
};

// 关闭LOADING
const hideLoading = function () {
  uni.hideLoading();
};

// 获取用户TOKEN
const getUserToken = function () {
  return uni.getStorageSync($config.keyname.userToken);
};

/**
 * 基础请求
 * @param {String} method 请求类型
 * @param {String} url 请求地址
 * @param {Object} data 请求数据
 * @param {Object} opts	配置参数
 */
api.base = function (method, url, data, opts) {
  return new Promise(async (resolve, reject) => {
    const options = Object.assign(
      {
        // 请求地址
        url: pathJoin($config.url.request, url),
        // 请求数据
        data: data || {},
        // 请求类型
        method: method || "post",
        // 数据类型
        dataType: "json",
        // 自动显示LOADING
        loading: true,
        // 启用错误自动拦截
        error: true,
        // 请求头设定
        header: {
          "content-type": "application/json",
          Authorization: "Bearer " + getAccessToken(), // 修改这里，使用新的获取token方法
        },
        // 设置显示LOADING的方法
        showLoading: showLoading,
        // 设置关闭LOADING的方法
        hideLoading: hideLoading,
      },
      opts || {}
    );
    if (options.loading && typeof options.showLoading == "function") {
      options.showLoading();
    }
    Request(options)
      .then(async (res) => {
        if (options.loading && typeof options.hideLoading == "function") {
          options.hideLoading();
        }
        switch (res.code) {
          // 请求正常
          case "00000":
            resolve(res);
            break;
          // 约定401为未登录状态
          case "A0230":
            try {
              // 尝试刷新token
              console.log("进入刷新请求");
              const refreshResult = await refreshToken();
              if (refreshResult) {
                // 刷新成功，更新header中的token并重新请求
                options.header.token = getAccessToken();
                try {
                  const db = await Request(options);
                  resolve(db);
                } catch (err) {
                  reject(err);
                }
              } else {
                // 刷新失败，执行登录
                // await api.login();
                options.header.token = getAccessToken();
                try {
                  const db = await Request(options);
                  resolve(db);
                } catch (err) {
                  reject(err);
                }
              }
            } catch (err) {
              reject(err);
            }
            break;
          // 其他错误请求
          default:
            if (options.error) {
              $app.popup.alert(res.msg || `${url}\r\n未知错误`, "数据请求");
            } else {
              reject(res);
            }
            break;
        }
      })
      .catch(async (err) => {
        if (err.data.code == "A0230") {
          try {
            // 尝试刷新token
            const refreshResult = await refreshToken();
            if (refreshResult) {
              // 刷新成功，更新header中的token并重新请求
              options.header.token = getAccessToken();
              try {
                const db = await Request(options);
                resolve(db);
              } catch (err) {
                reject(err);
              }
            } else {
              // 刷新失败，执行登录
              if (!isLoginPromptShown) {
                isLoginPromptShown = true;
                // 清除登录缓存
                $app.popup
                  .confirm(`${err.data.msg},点击确定去登录`, "提示", {
                    showCancel: true,
                  })
                  .then((confirmed) => {
                    isLoginPromptShown = false;
                    if (confirmed) {
                      uni.clearStorage();
                      uni.navigateTo({ url: "/pages/login/login" });
                    }
                  });
              }
            }
          } catch (err) {
            reject(err);
          }
        } else {
          $app.popup.alert(`服务器响应失败\r\n${err.data.msg}`, "数据请求");
        }
        /*失败处理，此处为非200状态码引起的错误*/
        options.hideLoading();
      });
  });
};

// 新增：获取accessToken的方法
const getAccessToken = function () {
  return uni.getStorageSync($config.keyname.accessToken);
};

// 新增：刷新token的方法
const refreshToken = async function () {
  const refreshToken = uni.getStorageSync($config.keyname.refreshToken);
  console.log("刷新token", refreshToken);
  if (!refreshToken) return false;
  try {
    const res = await Request({
      url: pathJoin($config.url.request, $config.api.refreshToken),
      method: "post",
      data: { refreshToken },
      header: {
        "content-type": "application/json",
      },
    });
    if (res.code === "00000") {
      uni.setStorageSync($config.keyname.accessToken, res.data.accessToken);
      uni.setStorageSync($config.keyname.refreshToken, res.data.refreshToken);
      return true;
    }
    return false;
  } catch (e) {
    return false;
  }
};

/**
 * POST请求
 * @param {String} url 请求地址
 * @param {Object} data 请求数据
 * @param {Object} opts 配置参数
 */
api.post = function (url, data, opts) {
  return api.base("post", url, data, Object.assign({}, opts));
};

/**
 * GET请求
 * @param {String} url 请求地址
 * @param {Object} data 请求数据
 * @param {Object} opts 配置参数
 */
api.get = function (url, data, opts) {
  return api.base("get", url, data, Object.assign({}, opts));
};
/**
 * PUT请求
 * @param {String} url 请求地址
 * @param {Object} data 请求数据
 * @param {Object} opts 配置参数
 */
api.put = function (url, data, opts) {
  return api.base("put", url, data, Object.assign({}, opts));
};

/**
 * 获取静态数据
 * @param {String} url 静态文件地址
 * @param {Object} data 参数数据
 * @param {Object} opts 配置参数
 */
api.static = function (url, data, opts) {
  return new Promise(async (resolve, reject) => {
    // 设置选项
    var _opts = Object.assign(
      {
        url: /^http/.test(url) ? url : API_BASE + (url || ""),
        data: Object.assign({ cache: Date.now() }, data),
      },
      opts || {}
    );
    uni.request({
      ..._opts,
      success: (res) => {
        resolve(res.data);
      },
    });
  });
};

/**
 * 文件上传
 * @param {String} file 文件临时路径
 * @param {Object} opts 上传参数
 */
api.upload = function (file, opts) {
  return new Promise((resolve, reject) => {
    const options = Object.assign(
      {
        // 请求地址
        url: pathJoin($config.url.upload, opts?.url || ""),
        // 请求数据
        filePath: file,
        // 自动显示LOADING
        loading: true,
        // 启用错误自动拦截
        error: true,
        // 请求头设定
        header: {
          token: uni.getStorageSync($config.keyname.userToken),
        },
        // 设置显示LOADING的方法
        showLoading: showLoading,
        // 设置关闭LOADING的方法
        hideLoading: hideLoading,
      },
      opts || {}
    );
  });
};

/**
 * 获取登录code
 */
api.userCode = function () {
  return new Promise((resolve, reject) => {
    uni.login({
      provider: "weixin",
      success: (res) => resolve(res.code),
      fail: (err) => reject(err),
    });
  });
};

/**
 * 自动登录
 * @param {Object} data 登录数据（非必填）
 */
api.login = function (data) {
  return new Promise(async (resolve, reject) => {
    const code = await api.userCode();
    api
      .post($config.api.login, { ...(data || {}), code })
      .then(async (res) => {
        // 保存 accessToken 和 refreshToken
        uni.setStorageSync($config.keyname.accessToken, res?.data?.accessToken);
        uni.setStorageSync(
          $config.keyname.refreshToken,
          res?.data?.refreshToken
        );
        // 保留原有的 userInfo 存储
        uni.setStorageSync($config.keyname.userInfo, res?.data?.userInfo);
        // 返回 accessToken 保持向后兼容
        resolve(res.data.accessToken);
      })
      .catch((err) => reject(err));
  });
};

export default api;
