import { headerOptions } from '@/config'
import { isObject } from '@vue/shared'
import { getToken } from './auth'
import dayjs from 'dayjs'

/**
 * @description 获取元素节点信息（在组件中的元素必须要传ctx）
 * @param  { String } selector 选择器 '.app' | '#app'
 * @param  { Boolean } all 是否多选
 * @param  { ctx } context 当前组件实例
 */
export const getRect = (selector: string, all = false, context?: any) => {
    return new Promise((resolve, reject) => {
        let qurey = uni.createSelectorQuery()
        if (context) {
            qurey = uni.createSelectorQuery().in(context)
        }
        qurey[all ? 'selectAll' : 'select'](selector)
            .boundingClientRect(function (rect) {
                if (all && Array.isArray(rect) && rect.length) {
                    return resolve(rect)
                }
                if (!all && rect) {
                    return resolve(rect)
                }
                reject('找不到元素')
            })
            .exec()
    })
}

/**
 * @description 获取当前页面实例
 */
export function currentPage() {
    const pages = getCurrentPages()
    const currentPage = pages[pages.length - 1]
    return currentPage || {}
}

/**
 * @description 后台选择链接专用跳转
 */
interface Link {
    path: string
    name?: string
    type?: string
    isTab?: boolean
    query?: Record<string, any>
}

export enum LinkTypeEnum {
    'SHOP_PAGES' = 'shop',
    'CUSTOM_LINK' = 'custom'
}

export function navigateTo(link: Link, navigateType: 'navigateTo' | 'reLaunch' = 'navigateTo') {
    const url = link.query ? `${link.path}?${objectToQuery(link.query)}` : link.path
    navigateType == 'navigateTo' && uni.navigateTo({ url })
    navigateType == 'reLaunch' && uni.reLaunch({ url })
}

/**
 * @description 是否为空
 * @param {unknown} value
 * @return {Boolean}
 */
export const isEmpty = (value: unknown) => {
    return value == null && typeof value == 'undefined'
}

/**
 * @description 显示消息提示框。
 * @param  { String } title 弹出内容
 * @param  { Number } duration 延时多少毫秒
 */
export const toast = (title: string | number | null, duration = 1000) => {
    uni.$u.toast(title)
}

/**
 * @description 对象格式化为Query语法
 * @param { Object } params
 * @return {string} Query语法
 */
export function objectToQuery(params: Record<string, any>): string {
    let query = ''
    for (const props of Object.keys(params)) {
        const value = params[props]
        const part = encodeURIComponent(props) + '='
        if (!isEmpty(value)) {
            if (isObject(value)) {
                for (const key of Object.keys(value)) {
                    if (!isEmpty(value[key])) {
                        const params = props + '[' + key + ']'
                        const subPart = encodeURIComponent(params) + '='
                        query += subPart + encodeURIComponent(value[key]) + '&'
                    }
                }
            } else {
                query += part + encodeURIComponent(value) + '&'
            }
        }
    }
    return query.slice(0, -1)
}
/**
 * @description 上传图片
 * @param  { String } path 选择的本地地址
 */
export function uploadFile(path: any, fileType = 'image') {
    return new Promise((resolve, reject) => {
        const token = getToken()
        uni.uploadFile({
            url: `${import.meta.env.VITE_APP_BASE_URL}/${
                headerOptions.urlPrefix
            }/upload/${fileType}`,
            filePath: path,
            name: 'file',
            header: {
                token
            },
            success: res => {
                const data = JSON.parse(res.data)
                if (data.code == 200) {
                    resolve(data.data)
                } else {
                    reject()
                }
            },
            fail: err => {
                reject()
            }
        })
    })
}

// 清除本地缓存
export const removeStorageData = (key: string) => {
    uni.removeStorage({
        key,
        success: res => {
            // console.log('清除成功', res)
        }
    })
}

/**
 * @description 组合异步任务
 * @param  { string } task 异步任务
 */
export function series(...task: Array<(_arg: any) => any>) {
    return function (): Promise<any> {
        return new Promise((resolve, reject) => {
            const iteratorTask = task.values()
            const next = (res?: any) => {
                const nextTask = iteratorTask.next()
                if (nextTask.done) {
                    resolve(res)
                } else {
                    Promise.resolve(nextTask.value(res))
                        .then(next)
                        .catch(() => {
                            setTimeout(() => {
                                reject()
                            }, 1000)
                        })
                }
            }
            next()
        })
    }
}

/**
 * @description 添加单位
 * @param {String | Number} value 值 100
 * @param {String} unit 单位 px em rem
 */
export const addUnit = (value: string | number, unit = 'rpx') => {
    return !Object.is(Number(value), NaN) ? `${value}${unit}` : value
}
/**路由跳转 */
export function router(url: string) {
    uni.navigateTo({ url })
}

/**添加金额符号 */
export function joinSuffix(value: number, suffix = '元') {
    return `${value}${suffix}`
}
/**转换日期 */
export function convertChineseMonthToDate(chineseMonth: string) {
    const regex = /(\d{4})年(\d{1,2})月/
    const matches = chineseMonth.match(regex)

    if (matches && matches.length === 3) {
        const year = matches[1]
        const month = matches[2].padStart(2, '0')
        return `${year}-${month}`
    } else {
        return ''
    }
}
/**金额千分位并保留2位小数 */
export function formatMoney(amount: any) {
    const fixedAmount = parseFloat(amount).toFixed(2)
    return amount && amount !== 0
        ? fixedAmount.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
        : amount === 0
        ? 0
        : '--'
}

/**判空 */
export function formatEmpty(value: any) {
    return value === '' ? '--' : value ?? '--'
}
/**设置单位 */
export function setUnit(value: any, unit: string) {
    return value || value === 0 ? `${value}${unit}` : '--'
}
/**日期格式化 */
export function formatDate(date: number, format = 'YYYY-MM-DD', concatName = '') {
    return dayjs(date).format(format).concat(concatName)
}

/**表单校验 */
export function validate(rules, datas) {
    return new Promise((resolve, reject) => {
        try {
            let valid = null
            Object.entries(rules).forEach(([key, rule]) => {
                let value = datas[key]
                if (Object.prototype.toString.call(value) === '[object String]') {
                    value = value.replace(/(^\s*)|(\s*$)/g, '')
                }
                if (Object.prototype.toString.call(rule) === '[object Object]') {
                    // 是否为空
                    const isEmpty = value === '' || value == null || value == undefined
                    // 是否必填
                    const disRequiredAbled = rule.required && isEmpty
                    // 自定义校验规则
                    let disCustomRuleAbled = false
                    if (rule.validator) {
                        rule.validator(rule, value, message => {
                            if (message) {
                                disCustomRuleAbled = true
                                rule = Object.assign({}, { message })
                            }
                        })
                    }
                    if (disRequiredAbled || disCustomRuleAbled) {
                        const message = rule.message
                        if (!valid) {
                            valid = { ...rule, message, field: key }
                        }
                    }
                }
            })
            resolve(valid)
        } catch (error) {
            reject(error)
        }
    })
}

/**loading */
export function loading(title: string) {
    return uni.showLoading({ title })
}
/**根据字节数获取文件大小，并转换成 KB、MB、GB、TB 等形式 */
export function formatFileSize(bytes: number) {
    const units = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
    let size = bytes
    let unitIndex = 0

    while (size >= 1024 && unitIndex < units.length - 1) {
        size /= 1024
        unitIndex++
    }

    // 保留两位小数，四舍五入
    size = Math.round(size * 100) / 100

    return `${size} ${units[unitIndex]}`
}

/**
 * @description 样式转换
 * 对象转字符串，或者字符串转对象
 * @param {object | string} customStyle 需要转换的目标
 * @param {String} target 转换的目的，object-转为对象，string-转为字符串
 * @returns {object|string}
 */
export function addStyle(customStyle, target = 'object') {
    // 字符串转字符串，对象转对象情形，直接返回
    if (
        empty(customStyle) ||
        (typeof customStyle === 'object' && target === 'object') ||
        (target === 'string' && typeof customStyle === 'string')
    ) {
        return customStyle
    }
    // 字符串转对象
    if (target === 'object') {
        // 去除字符串样式中的两端空格(中间的空格不能去掉，比如padding: 20px 0如果去掉了就错了)，空格是无用的
        customStyle = trim(customStyle)
        // 根据";"将字符串转为数组形式
        const styleArray = customStyle.split(';')
        const style = {}
        // 历遍数组，拼接成对象
        for (let i = 0; i < styleArray.length; i++) {
            // 'font-size:20px;color:red;'，如此最后字符串有";"的话，会导致styleArray最后一个元素为空字符串，这里需要过滤
            if (styleArray[i]) {
                const item = styleArray[i].split(':')
                style[trim(item[0])] = trim(item[1])
            }
        }
        return style
    }
    // 这里为对象转字符串形式
    let string = ''
    for (const i in customStyle) {
        // 驼峰转为中划线的形式，否则css内联样式，无法识别驼峰样式属性名
        const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
        string += `${key}: ${customStyle[i]};`
    }
    // 去除两端空格
    return trim(string)
}
/**
 * 判断是否为空
 */
function empty(value) {
    switch (typeof value) {
        case 'undefined':
            return true
        case 'string':
            if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true
            break
        case 'boolean':
            if (!value) return true
            break
        case 'number':
            if (value === 0 || isNaN(value)) return true
            break
        case 'object':
            if (value === null || value.length === 0) return true
            for (const i in value) {
                return false
            }
            return true
    }
    return false
}
/**
 * @description 去除空格
 * @param String str 需要去除空格的字符串
 * @param String pos both(左右)|left|right|all 默认both
 */
function trim(str, pos = 'both') {
    str = String(str)
    if (pos == 'both') {
        return str.replace(/^\s+|\s+$/g, '')
    }
    if (pos == 'left') {
        return str.replace(/^\s*/, '')
    }
    if (pos == 'right') {
        return str.replace(/(\s*$)/g, '')
    }
    if (pos == 'all') {
        return str.replace(/\s+/g, '')
    }
    return str
}

/**
 * 防止小程序多次点击跳转
 * @param {*} obj
 * @returns
 */
export function throttle(fn: any, gapTime: number) {
    if (gapTime == null || gapTime == undefined) {
        gapTime = 1500
    }

    let _lastTime = null

    // 返回新的函数
    return function () {
        const _nowTime = +new Date()
        if (_nowTime - _lastTime > gapTime || !_lastTime) {
            fn.apply(this, arguments) //将this和参数传给原函数
            _lastTime = _nowTime
        }
    }
}
