import Vue from 'vue'
import md5Libs from "uview-ui/libs/function/md5";
import globalVariable from "../global-variable";

export class CommonUtil {

    // ----------------------------------------------原生js----------------------------------------------

    /**
     * 生成签名
     *
     * @return
     */
    static generateSign(timestamp) {
        return md5Libs.md5(md5Libs.md5(timestamp + globalVariable.key) + timestamp + globalVariable.key);
    }

    /**
     * 随机生成uuid
     * @returns {string}
     */
    static generateUUID() {
        var s = []
        var hexDigits = '0123456789abcdef'
        for (var i = 0; i < 36; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
        }
        s[14] = '4' // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1) // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23] = '-'

        var uuid = s.join('')
        return uuid
    }

    /**
     * 随机生成uuid
     */
    static randomUUID() {
        return this.generateUUID();
    }

    /**
     * 生成范围随机数
     * @param max
     * @param min
     * @returns {number}
     */
    static random(max, min) {
        return Math.round(Math.random() * (max - min) + min);
    }

    /**
     * 生成code编号
     *
     * @return
     */
    static generateCode() {
        let identifyingCode = parseInt((Math.random() * 9 + 1) * 100000 + '');
        return this.dateFormat(new Date(), 'yyyyMMddHHmmss') + identifyingCode;
    }

    /**
     * 获取手机端的屏幕宽度
     */
    static getScreenWidth() {
        // 小程序会报错
        // let width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
        let width = uni.getSystemInfoSync().screenWidth;
        console.log(width);
        return width;
    }

    /**
     * 获取手机端的屏幕高度
     */
    static getScreenHeight() {
        // 微信小程序会报错
        // let height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
        let height = uni.getSystemInfoSync().screenHeight;
        console.log(height);
        return height;
    }

    /**
     * 生成包含数字、大写字母、小写字母的随机数
     * @param length
     * @returns {string}
     */
    static randomStr(length = 4) {  //封装，以便日后使用。
        //创建一个空字符，用于存放随机数/字母
        var strData = "";
        //生成随机字符库 (验证码四位，随机数三种，取公倍数12,所以循环4次。也可以是120次，1200次。)
        for (var i = 0; i < length; i++) {
            var num = this.random(0, 9);//生成0-9的随机数
            var az = String.fromCharCode(this.random(97, 122));//生成a-z
            var AZ = String.fromCharCode(this.random(65, 90));//生成A-Z

            strData = strData + num + az + AZ;//将生成的字符进行字符串拼接
        }
        // 开始真正的随机(从随机字符库中随机取出四个)
        var str = "";
        for (var i = 0; i < 4; i++) {
            str += strData[this.random(0, strData.length - 1)]
        }
        return str;
    }

    /**
     * 合并对象值
     */
    static mergeData(_self, target, ...sources) {
        for (let index in sources) {
            let source = sources[index]
            for (let attrName in source) {
                _self.$set(target, attrName, source[attrName])
                if (typeof source[attrName] === 'object') {
                    this.mergeData(_self, target[attrName], source[attrName])
                }
            }
        }
        _self.$forceUpdate();
        return target
    }

    /**
     * 删除左右两端的空格
     * @param str
     * @returns {*}
     */
    static trim(str) {
        let result = str
        try {
            result = str.replace(/(^\s*)|(\s*$)/g, '')
        } catch (e) {
            // 非字符串没有.replace方法
        }
        return result
    }

    /**
     * 对象转url参数
     * @param obj
     * @param isEncodeURI
     * @returns {string}
     */
    static objectToUrlParams(obj, isEncodeURI) {
        // 优化参数
        for (let attrName in obj) {
            if (obj[attrName] === undefined || obj[attrName] == null || obj[attrName] === 'undefined' || obj[attrName] === 'null' || CommonUtil.trim(obj[attrName]) === '') {
                delete obj[attrName]
            }
        }
        if (!isEncodeURI) {  // 是否编码参数
            return Object.keys(obj).map(function (key) {
                return ''.concat(key, '=').concat(obj[key])
            }).join('&')
        } else {
            return Object.keys(obj).map(function (key) {
                return ''.concat(encodeURIComponent(key), '=').concat(encodeURIComponent(obj[key]))
            }).join('&')
        }
    };

    /**
     * 时间字符串转时间戳  2020-09-27 17:06:21  --> 1601197581000
     * @param datetimeStr
     */
    static datetimeStrToTimestamp(datetimeStr) {
        datetimeStr = datetimeStr.substring(0, 19);
        datetimeStr = datetimeStr.replace(/-/g, '/'); //必须把日期'-'转为'/'
        let timestamp = new Date(datetimeStr).getTime();
        return timestamp;
    }

    /**
     * 格式化日期
     * @param date
     * @param fmt yyyy-MM-dd HH:mm:ss
     * @returns {*}
     */
    static dateFormat(date, fmt = 'yyyy-MM-dd HH:mm:ss') {
        // 如果是日期字符串，则转成日志类型
        if (typeof date === 'string') {
            date = new Date(date);
        }

        let ret;
        const opt = {
            "y+": date.getFullYear().toString(),        // 年
            "M+": (date.getMonth() + 1).toString(),     // 月
            "d+": date.getDate().toString(),            // 日
            "H+": date.getHours().toString(),           // 时
            "m+": date.getMinutes().toString(),         // 分
            "s+": date.getSeconds().toString()          // 秒
            // 有其他格式化字符需求可以继续添加，必须转化成字符串
        };
        for (let k in opt) {
            ret = new RegExp("(" + k + ")").exec(fmt);
            if (ret) {
                fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
            }
        }
        return fmt;
    }

    /**
     * 获取两个时间相差的天数
     * @param date1
     * @param date2
     * @returns {number}
     */
    static getDiffDays(date1, date2) {
        if (typeof date1 === 'string') {
            date1 = new Date(date1);
        }
        if (typeof date2 === 'string') {
            date2 = new Date(date2);
        }
        /*获取之间的天数*/
        let diffDays = (date2.getTime() - date1.getTime()) / (3600 * 24 * 1000);
        return parseInt(diffDays);
    }

    /**
     * 删除对象中所有的null、undefined属性值
     */
    static deleteNullAttrInObject(obj, removeEmptyStr = true) {
        for (var key in obj) {
            if (obj[key] === null) {
                delete obj[key]
            }
            if (obj[key] === undefined) {
                delete obj[key]
            }
            if (removeEmptyStr && obj[key] === '') {
                delete obj[key]
            }
            if (Array.isArray(obj[key]) && obj[key].length === 0) {  // 删除空数组[]属性
                delete obj[key]
            }
        }
        return obj
    }

    static urlParamsAppendToUrl(url, urlParams) {
        if (urlParams) {
            if (url.indexOf("?") === -1) {
                url = url + "?" + this.objectToUrlParams(urlParams);
            } else {
                url = url + "&" + this.objectToUrlParams(urlParams);
            }
        }
        return url;
    }

    /**
     * 毫秒转换友好的显示格式
     * 输出格式：21小时前
     * @param  {[type]} time [description]
     * @return {[type]}      [description]
     */
    static showTime(datetime) {

        //获取js 时间戳
        var time = new Date().getTime();

        //去掉 js 时间戳后三位，与php 时间戳保持一致
        time = parseInt((time - this.datetimeStrToTimestamp(datetime)) / 1000 + '');

        //存储转换值
        var s;
        if (time == 0) {
            return '刚刚';
        } else if (time < 60) {
            return time + '秒前';
        } else if ((time < 60 * 60) && (time >= 60)) {
            //超过十分钟少于1小时
            s = Math.floor(time / 60);
            return s + '分钟前';
        } else if ((time < 60 * 60 * 24) && (time >= 60 * 60)) {
            //超过1小时少于24小时
            s = Math.floor(time / 60 / 60);
            return s + '小时前';
        } else if ((time < 60 * 60 * 24 * 30) && (time >= 60 * 60 * 24)) {
            //超过1天少于30天内
            s = Math.floor(time / 60 / 60 / 24);
            return s + '天前';
        } else {
            //超过3天
            // var date = new Date(parseInt(datetime) * 1000);
            // return date.getFullYear() + '/' + (date.getMonth() + 1) + '/' + date.getDate();
            return this.dateFormat(datetime, 'MM-dd HH:mm');
        }
    }

    /**
     * 将字符串编码成base64
     * @param str
     * @returns {string}
     */
    static toBase64Encode(str) {
        var c1, c2, c3;
        var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var i = 0, len = str.length, string = '';

        while (i < len) {
            c1 = str.charCodeAt(i++) & 0xff;
            if (i == len) {
                string += base64EncodeChars.charAt(c1 >> 2);
                string += base64EncodeChars.charAt((c1 & 0x3) << 4);
                string += "==";
                break;
            }
            c2 = str.charCodeAt(i++);
            if (i == len) {
                string += base64EncodeChars.charAt(c1 >> 2);
                string += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
                string += base64EncodeChars.charAt((c2 & 0xF) << 2);
                string += "=";
                break;
            }
            c3 = str.charCodeAt(i++);
            string += base64EncodeChars.charAt(c1 >> 2);
            string += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
            string += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
            string += base64EncodeChars.charAt(c3 & 0x3F)
        }
        return string
    }

    /**
     * 添加属性别名
     * @param object
     * @param alias
     * {
     * "name": "label", 给name属性取个别名label
     * "code": "value" 给code属性取个别名value
     * }
     */
    static objectAlias(object, alias = {'name': 'label', 'code': 'value'}) {
        if (!object) {
            return;
        }
        // 数组
        if (Array.isArray(object)) {
            object.forEach(item => {
                for (let attrName in alias) {
                    // 将一个属性取一个别名
                    if (attrName.indexOf(",") === -1) {
                        item[alias[attrName]] = item[attrName];
                    } else {// 将多个属性取同一个别名，每个属性名/值以逗号隔开
                        let attrNames = attrName.split(",");
                        let value = [];
                        for (let i = 0; i < attrNames.length; i++) {
                            value.push(item[attrNames[i]]);
                        }
                        item[alias[attrName]] = value.join(",");
                    }
                }

                if (item.children) {
                    this.objectAlias(item.children, alias);
                }
            });
        } else {  // 对象
            for (let attrName in alias) {
                if (attrName.indexOf(",") === -1) {
                    object[alias[attrName]] = object[attrName];
                } else {
                    let attrNames = attrName.split(",");
                    let value = [];
                    for (let i = 0; i < attrNames.length; i++) {
                        value.push(item[attrNames[i]]);
                    }
                    item[alias[attrName]] = value.join(",");
                }
            }
            if (object.children) {
                this.objectAlias(object.children, alias);
            }
        }
        return object;
    }

    /**
     * 刷新对象值
     * @param _selfVue
     * @param obj
     */
    static refreshObj(_selfVue, obj) {
        const _self = this;
        for (let key in obj) {
            //排除掉原型继承而来的属性
            if (!obj.hasOwnProperty(key)) {
                return;
            }

            console.log(key, obj[key]);
            if (typeof obj[key] === 'object' || typeof obj[key] === 'function') {
                _self.refreshObj(_selfVue, obj[key]);
            } else if (Array.isArray(obj[key])) {
                obj[key].forEach((item) => {
                    _self.refreshObj(_selfVue, item);
                })
            } else {
                _selfVue.$set(obj, key, obj[key]);
            }
        }
    }

    /**
     * 是否是JSON字符串
     * @param str
     * @returns {boolean}
     */
    static isJSON(str) {
        if (typeof str == 'string') {
            try {
                var obj = JSON.parse(str);
                if (typeof obj == 'object' && obj) {
                    return true;
                } else {
                    return false;
                }
            } catch (e) {
                console.log('error：' + str + '!!!' + e);
                return false;
            }
        }
    }

    /**
     * 是否是数字
     * @param checkVal
     * @returns {boolean}
     */
    static isNumber(checkVal) {
        var reg = /^-?[1-9][0-9]?.?[0-9]*$/;
        return reg.test(checkVal);
    }

    /**
     * 提取url中的参数
     */
    static getUrlParams(url) {
        // url不存在参数
        if (url.indexOf("?") === -1) {
            return {};
        }
        // http://www.baidu.com/test?a=1&b=2
        let params = url.split("?")[1];  // a=1&b=2
        params = params.split("&"); // ['a=1', 'b=2']
        let urlParams = {};
        params.forEach(item => {
            let keyValue = item.split("="); // 'a=1'  --> ['a', '1']
            urlParams[keyValue[0]] = keyValue[1];
        });
        return urlParams;  // {a: 1, b: 2}
    }

    // ----------------------------------------------uview-ui----------------------------------------------

    /**
     * 深度克隆
     * 当我们将一个对象(变量A)赋值给另一个变量(变量B)时，修改变量B，因为对象引用的特性，导致A也同时被修改，
     * 所以有时候我们需要将A克隆给B，这样修改B的时候，就不会 导致A也被修改。
     * @param object
     * @returns {*}
     */
    static deepClone(object = {}) {
        return Vue.prototype.$u.deepClone(object)
    }

    /**
     * 对象深度合并
     * 在ES6中，我们可以很方便的使用Object.assign进行对象合并，但这只是浅层的合并，如果对象的属性为数组或者对象的时候，会导致属性内部的值丢失。
     * 注意： 此处合并不同于Object.assign，因为Object.assign(a, b)会修改a的值为最终的结果(这往往不是我们所期望的)，但是deepMerge(a, b)并不会修改a的值。
     * @param target
     * @param source
     * @returns {boolean|*}
     */
    static deepMerge(target = {}, source = {}) {
        return Vue.prototype.$u.deepMerge(target, source)
    }

    /**
     * md5加密
     * @param value
     * console.log(md5Libs.md5('uView'))  // 结果为：55c859b4750225eb1cdbd9e0403ee274
     */
    static md5(value) {
        return md5Libs.md5(value)
    }


    // ----------------------------------------------uni-app原生api----------------------------------------------
    static navigateTo(url, urlParams, objParams) {

        // 兼容部分手机机型不能从导航事件中获取objParams问题。
        globalVariable.objParams = objParams;

        return new Promise(function (resolve, reject) {
            if (urlParams) {
                if (url.indexOf("?") === -1) {
                    url = url + "?" + CommonUtil.objectToUrlParams(urlParams);
                } else {
                    url = url + "&" + CommonUtil.objectToUrlParams(urlParams);
                }
            }
            uni.navigateTo({
                url: url,
                success: function (res) {
                    if (objParams) {
                        // 通过eventChannel向被打开页面传送数据
                        res.eventChannel.emit('objParams', objParams)
                    }
                    resolve(res);
                }
            })
        });
    }

    /**
     * @param title
     * @param duration
     * @param icon
     success、warn、error    显示成功图标，此时 title 文本最多显示 7 个汉字长度。默认值
     loading    显示加载图标，此时 title 文本最多显示 7 个汉字长度。    支付宝小程序不支持
     none    不显示图标，此时 title 文本在小程序最多可显示两行，App仅支持单行显示。
     * @returns {Promise<any>}
     */
    static toast(title, duration = 1500, icon = 'none') {
        return new Promise(function (resolve, reject) {
            uni.showToast({
                title: title,
                icon: icon,
                mask: true,  // 是否显示透明蒙层，防止触摸穿透，默认：false
                duration: duration,  // 提示的延迟时间，单位毫秒，默认：1500
                complete: () => {
                    setTimeout(function () {
                        resolve('提示时间已完成');
                    }, duration);
                }
            });
        });
    }

    /**
     * 执行完后直接跳转页面
     */
    static toastNavigateTo(title, url, urlParams, objParams) {
        const _self = this;

        // 兼容部分手机机型不能从导航事件中获取objParams问题。
        globalVariable.objParams = objParams;

        return new Promise(function (resolve, reject) {
            if (title) {
                this.toast(title).then(() => {
                    uni.navigateTo({
                        url: _self.urlParamsAppendToUrl(url, urlParams),
                        success: function (res) {
                            if (objParams) {
                                // 通过eventChannel向被打开页面传送数据
                                res.eventChannel.emit('objParams', objParams)
                            }
                            resolve(res);
                        }
                    })
                })
            } else {
                uni.navigateTo({
                    url: _self.urlParamsAppendToUrl(url, urlParams),
                    success: function (res) {
                        if (objParams) {
                            // 通过eventChannel向被打开页面传送数据
                            res.eventChannel.emit('objParams', objParams)
                        }
                        resolve(res);
                    }
                })
            }
        });
    }

    /**
     * 执行完后直接返回上一个页面
     */
    static toastNavigateBack(title, delta = 1) {
        const _self = this;
        return new Promise(function (resolve, reject) {
            if (title) {
                _self.toast(title).then(() => {
                    uni.navigateBack({
                        delta: delta
                    });
                    resolve();
                })
            } else {
                uni.navigateBack({
                    delta: delta
                });
                resolve();
            }
        });
    }

    /**
     * 执行完毕后关闭所有页面并打开指定页面
     */
    static toastReLaunch(title, url, urlParams) {
        const _self = this;
        if (title) {
            _self.toast(title).then(() => {
                uni.reLaunch({
                    url: _self.urlParamsAppendToUrl(url, urlParams)
                });
            })
        } else {
            uni.reLaunch({
                url: _self.urlParamsAppendToUrl(url, urlParams)
            });
        }
    }

    /**
     * 执行完毕后跳转到 tabBar 页面，并关闭其他所有非 tabBar 页面。
     */
    static toastSwitchTab(title, url, urlParams) {
        const _self = this;
        if (title) {
            _self.toast(title).then(() => {
                uni.switchTab({
                    url: _self.urlParamsAppendToUrl(url, urlParams)
                });
            })
        } else {
            uni.switchTab({
                url: _self.urlParamsAppendToUrl(url, urlParams)
            });
        }
    }

    /**
     {
            title: '删除图片',
            content: '确定要删除该图片？',
            showCancel: true, // 是否显示取消按钮
            cancelText:"否", // 默认是“取消”
            cancelColor:'skyblue', // 取消文字的颜色
            confirmText:"是", // 默认是“确定”
            confirmColor: 'skyblue', // 确定文字的颜色
            success: function (res) {
                if (res.cancel) { // 点击取消,默认隐藏弹框
                } else { // 点击确定

                    temp.splice(index, 1),
                        that.setData({
                            tempFilePaths: temp,
                        })
                }
            },
            fail: function (res) { }, // 接口调用失败的回调函数
            complete: function (res) { } // 接口调用结束的回调函数（调用成功、失败都会执行）
        }

     CommonUtil.alert({
        title: '提示！',
        content: '确认提交吗？',
        showCancel: true, // 是否显示取消按钮
        success: function (res) {
            if (res.cancel) { // 点击取消,默认隐藏弹框
            } else { // 点击确定

            }
        }
     });

     * @param opts
     */
    static alert(opts) {
        return new Promise(function (resolve, reject) {
            if (typeof opts === 'string') {
                uni.showModal({
                    title: '提示',
                    content: opts,
                    showCancel: false, // 是否显示取消按钮
                    success: function (res) {
                        if (res.cancel) { // 点击取消,默认隐藏弹框
                        } else { // 点击确定
                        }
                        resolve();
                    }
                });
            } else {
                uni.showModal(opts);
                resolve();
            }
        });
    }

    /**
     * 执行完后直接跳转页面
     */
    static alertNavigateTo(title, url, urlParams, objParams) {
        const _self = this;

        // 兼容部分手机机型不能从导航事件中获取objParams问题。
        globalVariable.objParams = objParams;

        return new Promise(function (resolve, reject) {
            if (title) {
                uni.showModal({
                    title: '提示！',
                    content: title,
                    showCancel: false, // 是否显示取消按钮
                    success: function (res) {
                        if (res.cancel) { // 点击取消,默认隐藏弹框
                        } else { // 点击确定
                            uni.navigateTo({
                                url: _self.urlParamsAppendToUrl(url, urlParams),
                                success: function (res) {
                                    if (objParams) {
                                        // 通过eventChannel向被打开页面传送数据
                                        res.eventChannel.emit('objParams', objParams)
                                    }
                                    resolve(res);
                                }
                            })
                        }
                    }
                });
            } else {
                uni.navigateTo({
                    url: _self.urlParamsAppendToUrl(url, urlParams),
                    success: function (res) {
                        if (objParams) {
                            // 通过eventChannel向被打开页面传送数据
                            res.eventChannel.emit('objParams', objParams)
                        }
                        resolve(res);
                    }
                })
            }
        });
    }

    /**
     * 执行完后直接返回上一个页面
     */
    static alertNavigateBack(title, delta = 1) {
        const _self = this;
        return new Promise(function (resolve, reject) {
            if (title) {
                uni.showModal({
                    title: '提示！',
                    content: title,
                    showCancel: false, // 是否显示取消按钮
                    success: function (res) {
                        if (res.cancel) { // 点击取消,默认隐藏弹框
                        } else { // 点击确定
                            uni.navigateBack({
                                delta: delta
                            });
                        }
                        resolve();
                    }
                });
            } else {
                uni.navigateBack({
                    delta: delta
                });
                resolve();
            }
        });
    }

    /**
     * 执行完毕后关闭所有页面并打开指定页面
     */
    static alertReLaunch(title, url, urlParams) {
        const _self = this;
        if (title) {
            uni.showModal({
                title: '提示！',
                content: title,
                showCancel: false, // 是否显示取消按钮
                success: function (res) {
                    if (res.cancel) { // 点击取消,默认隐藏弹框
                    } else { // 点击确定
                        uni.reLaunch({
                            url: _self.urlParamsAppendToUrl(url, urlParams)
                        });
                    }
                }
            });
        } else {
            uni.reLaunch({
                url: _self.urlParamsAppendToUrl(url, urlParams)
            });
        }
    }

    /**
     * 执行完毕后跳转到 tabBar 页面，并关闭其他所有非 tabBar 页面。
     */
    static alertSwitchTab(title, url, urlParams) {
        const _self = this;
        if (title) {
            uni.showModal({
                title: '提示！',
                content: title,
                showCancel: false, // 是否显示取消按钮
                success: function (res) {
                    if (res.cancel) { // 点击取消,默认隐藏弹框
                    } else { // 点击确定
                        uni.switchTab({
                            url: _self.urlParamsAppendToUrl(url, urlParams)
                        });
                    }
                }
            });
        } else {
            uni.switchTab({
                url: _self.urlParamsAppendToUrl(url, urlParams)
            });
        }
    }
}
