const app = {};

app.sys = class appSystem {
  /**
   * 环境版本判定回调
   * @param {Object.Function} callbacks 回调执行方法
   */
  static envVersion(callbacks) {
    if (!uni.getAccountInfoSync) return;
    const current = uni.getAccountInfoSync()?.miniProgram?.envVersion;
    const fn = callbacks[current];
    if (fn && typeof fn == "function") fn();
  }
};

app.url = class appUrl {
  /**
   * 跳转到地址
   * @param {String} url path字符串
   * @param {Boolean} mode 跳转模式; false时关闭当前窗口跳转 | null时关闭所有窗口跳转 | 默认为打开新窗口跳转(最多支持10层,页面栈超过10层后默认为false模式);
   */
  static goto(url, mode) {
    return new Promise((resolve, reject) => {
      const success = () => resolve();
      const fail = (err) => {
        // 仅对tabBar页面尝试switchTab,且移除参数
        const urlWithoutParams = url.split('?')[0];
        const tabBarPages = ['/pages/index/index', '/pages/map/map', '/pages/my/my'];
        if (tabBarPages.includes(urlWithoutParams)) {
          uni.switchTab({ url: urlWithoutParams, success, fail: () => reject(err) });
        } else {
          reject(err);
        }
      };
      if (mode === false) return uni.redirectTo({ url, fail, success });
      if (mode === null) return uni.reLaunch({ url, fail, success });
      if (getCurrentPages().length < 10) {
        uni.navigateTo({ url, fail, success });
      } else {
        uni.redirectTo({ url, fail, success });
      }
    });
  }

  /**
   * 返回页面
   * @param {int} delta 返回级数
   */
  static back(delta) {
    const pages = getCurrentPages();
    const targetPageIndex = pages.length - 1 - (delta || 1);

    if (targetPageIndex >= 0 && targetPageIndex < pages.length) {
      const targetPage = pages[targetPageIndex];
      uni.navigateBack({
        delta: delta || 1,
        success: () => {
          // 延迟执行刷新，确保页面已经返回
          setTimeout(() => {
            if (targetPage.onLoad) targetPage.onLoad(targetPage.options);
            if (targetPage.onShow) targetPage.onShow();
          }, 100);
        },
      });
    } else {
      uni.navigateBack({ delta: delta || 1 });
    }
  }

  /**
   * 刷新页面,会触发onLoad和onShow等钩子
   */
  static refresh() {
    const pages = getCurrentPages();
    const current = pages[pages.length - 1];
    const url = current.$page.fullPath;
    app.urlGoto(url, false);
  }

  /**
   * 打开新窗口并传递数据
   * @param {String} url path字符串
   * @param {any} data 传递数据
   */
  static open(url, data) {
    const pages = getCurrentPages();
    const current = pages[pages.length - 1].$page.fullPath;
    uni.navigateTo({
      url,
      success: (res) => {
        res.eventChannel.emit(`OPEN-DATA[${current}]`, data);
      },
    });
  }

  /**
   * 获取open方法发送到数据
   * @param {Component} component 组件对象
   */
  static load(component) {
    return new Promise((resolve, reject) => {
      if (component == undefined) return console.error(`app.url.load(this);`);
      const pages = getCurrentPages();
      const current = pages[pages.length - 2]?.$page?.fullPath;
      const caller = component?.getOpenerEventChannel;
      const channel = caller && caller.call(component);
      if (channel && channel.on)
        channel.on(`OPEN-DATA[${current}]`, (data) => resolve(data));
    });
  }

  /**
   * 打开其他小程序
   * @param {String} appid 小程序APPID
   * @param {String} path 要打开的程序路径
   * @param {Object} data 要传递给小程序狗子的参数
   */
  static applet(appid, path, data) {
    return new Promise((resolve, reject) => {
      uni.navigateToMiniProgram({
        appId: appid,
        path: path,
        extraData: data || {},
        success: (res) => resolve(res),
      });
    });
  }
};

app.storage = class appStorage {
  /**
   * 设置本地缓存数据
   * @param {String} key 数据键名
   * @param {any} data 存储数据,支持对象
   */
  static set(key, data) {
    try {
      uni.setStorageSync(key, data);
    } catch (err) {
      console.error("app.setStorageSync error: ", err);
    }
  }

  /**
   * 获取本地缓存数据
   * @param {String} key 数据键名
   */
  static get(key) {
    return uni.getStorageSync(key);
  }

  /**
   * 清除键缓存数据
   * @param {Object} key 数据键名
   */
  static remove(key) {
    uni.removeStorageSync(key);
  }

  /**
   * 清理所有缓存数据
   */
  static clear() {
    uni.clearStorageSync();
  }
};

app.math = class appMath {
  /**
   * 浮点精确相加
   * @param {Number} arg1		参数1
   * @param {Number} arg2		参数2
   */
  static add(arg1, arg2) {
    var r1, r2, m;
    try {
      r1 = arg1.toString().split(".")[1].length;
    } catch (e) {
      r1 = 0;
    }
    try {
      r2 = arg2.toString().split(".")[1].length;
    } catch (e) {
      r2 = 0;
    }
    m = Math.pow(10, Math.max(r1, r2));
    return (arg1 * m + arg2 * m) / m;
  }

  /**
   * 浮点精确相减
   * @param {Number} arg1		参数1
   * @param {Number} arg2		参数2
   */
  static sub(arg1, arg2) {
    var r1, r2, m, n;
    try {
      r1 = arg1.toString().split(".")[1].length;
    } catch (e) {
      r1 = 0;
    }
    try {
      r2 = arg2.toString().split(".")[1].length;
    } catch (e) {
      r2 = 0;
    }
    m = Math.pow(10, Math.max(r1, r2));
    n = (r1 = r2) ? r1 : r2;
    return ((arg1 * m - arg2 * m) / m).toFixed(n);
  }

  /**
   * 浮点精确相乘
   * @param {Number} arg1		参数1
   * @param {Number} arg2		参数2
   */
  static mul(arg1, arg2) {
    var m = 0,
      s1 = arg1.toString(),
      s2 = arg2.toString();
    try {
      m += s1.split(".")[1].length;
    } catch (e) {}
    try {
      m += s2.split(".")[1].length;
    } catch (e) {}
    return (
      (Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) /
      Math.pow(10, m)
    );
  }

  /**
   * 浮点精确相除
   * @param {Number} arg1		参数1
   * @param {Number} arg2		参数2
   */
  static div(arg1, arg2) {
    var t1 = 0,
      t2 = 0,
      r1,
      r2;
    try {
      t1 = arg1.toString().split(".")[1].length;
    } catch (e) {}
    try {
      t2 = arg2.toString().split(".")[1].length;
    } catch (e) {}
    r1 = Number(arg1.toString().replace(".", ""));
    r2 = Number(arg2.toString().replace(".", ""));
    return (r1 / r2) * Math.pow(10, t2 - t1);
  }
};

app.date = class appDate {
  /**
   * 日期格式化
   * @param {String} fmt 格式规则
   * @param {String | Date} date 需要格式化的日期
   */
  static format(fmt, date) {
    if (!fmt) fmt = "yyyy-MM-dd hh:mm:sss";
    if (typeof date === "string") date = new Date(date.replaceAll("-", "/"));
    if (!date) date = new Date();
    var o = {
      "M+": date.getMonth() + 1, //月份
      "d+": date.getDate(), //日
      "h+": date.getHours(), //小时
      "m+": date.getMinutes(), //分
      "s+": date.getSeconds(), //秒
      "q+": Math.floor((date.getMonth() + 3) / 3), //季度
      S: date.getMilliseconds(), //毫秒
    };
    if (/(y+)/.test(fmt))
      fmt = fmt.replace(
        RegExp.$1,
        (date.getFullYear() + "").substr(4 - RegExp.$1.length)
      );
    for (var k in o)
      if (new RegExp("(" + k + ")").test(fmt))
        fmt = fmt.replace(
          RegExp.$1,
          RegExp.$1.length == 1
            ? o[k]
            : ("00" + o[k]).substr(("" + o[k]).length)
        );
    return fmt;
  }
};

app.popup = class appPopup {
  /**
   * 对话框
   * @param {String} content 弹窗内容
   * @param {String} title 弹窗标题
   * @param {Object} opts 参数
   */
  static confirm(content, title, opts) {
    return new Promise((resolve, reject) => {
      if (!title && title == null) title = "温馨提示";
      opts = Object.assign(
        {
          title: title,
          content: content,
          confirmColor: "#007AFF",
          success: (res) => resolve(res.confirm == true),
          fail: (err) => reject(err),
        },
        opts
      );
      uni.showModal(opts);
    });
  }

  /**
   * 提示框
   * @param {String} content 弹窗内容
   * @param {String} title 弹窗标题
   */
  static alert(content, title) {
    return appPopup.confirm(content, title || null, { showCancel: false });
  }

  /**
   * 轻提示
   * @param {String} content 提示内容
   * @param {Object} opts 参数
   */
  static toast(content, opts) {
    uni.showToast(
      Object.assign(
        {
          title: content,
          position: "bottom",
          duration: 2000,
          icon: "none",
        },
        opts
      )
    );
  }

  /**
   * 加载条
   * @param {Boolean} visible 显示
   * @param {Object} opts 参数
   */
  static loading(visible, opts) {
    if (visible) {
      uni.showLoading(Object.assign({ title: "载入中", mask: true }, opts));
      const timeout = opts?.timeout || 45 * 1000;
      setTimeout(() => appPopup.loading(false), timeout);
    } else {
      uni.hideLoading();
    }
  }

  /**
   * 操作菜单
   * @param {Array} data 列表数据
   * @param {String} key 指定显示字段
   * @param {Object} opts 参数
   */
  static sheet(data, key, opts) {
    return new Promise((resolve, reject) => {
      uni.showActionSheet(
        Object.assign(
          {
            title: "",
            itemList: data.map((item) =>
              key ? item[key] || String(item) : String(item)
            ),
            success: (res) =>
              resolve({ index: res.tapIndex, data: data[res.tapIndex] }),
          },
          opts
        )
      );
    });
  }
};

app.map = class appMap {
  /**
   * 获取当前位置坐标
   * @param {Boolean} high 是否调用高精度接口
   * @param {Object} opts 参数
   */
  static get(high, opts) {
    return new Promise((resolve, reject) => {
      const OPTS = Object.assign(
        {
          success: (res) => {
            console.log(res);
          },
          fail: (err) => {
            console.log(err);
          },
        },
        opts
      );
      high ? uni.getLocation(OPTS) : uni.getFuzzyLocation(OPTS);
    });
  }
};

app.act = class appAct {
  /**
   * 拨打电话
   * @param {String} phone
   */
  static callPhone(phone) {
    uni.makePhoneCall({ phoneNumber: phone });
  }

  /**
   * 调用扫描
   * @param {Object} opts 参数配置,详细查看 https://uniapp.dcloud.net.cn/api/system/barcode.html
   */
  static scan(opts) {
    return new Promise((resolve, reject) => {
      uni.scanCode(
        Object.assign(
          {},
          {
            success: (res) => resolve(res),
            // fail: err=>reject(err),
          },
          opts
        )
      );
    });
  }

  /**
   * 获取节点信息
   * @param {Component} component 组件
   * @param {String} selector 类似于 CSS 的选择器
   * @param {Boolean} multi 是否多节点
   */
  static selectorQuery(component, selector, multi) {
    return new Promise((resolve, reject) => {
      const query = uni
        .createSelectorQuery()
        .in(component)
        [multi ? "selectAll" : "select"](selector);
      query
        .boundingClientRect((data) => {
          if (data) resolve(data);
        })
        .exec();
    });
  }

  /**
   * 复制文本到剪贴板
   * @param {String} str 需要复制的文本
   */
  static copy(str) {
    return new Promise((resolve, reject) => {
      uni.setClipboardData({
        data: "hello",
        success: resolve(),
        fail: (err) => reject(err),
      });
    });
  }

  /**
   * 客服服务
   * @param {Object} id
   * @param {Object} url
   */
  static customerService(id, url) {
    return new Promise((resolve, reject) => {
      wx.openCustomerServiceChat({
        extInfo: { url: url },
        corpId: id,
        success: (res) => resolve(res),
        fail: (err) => reject(err),
      });
    });
  }
};

module.exports = app;
