/**
 * @name: 支付工具方法
 * @author: kahu4
 * @date: 2023-11-07 11:42
 * @description：支付工具方法 请使用try catch抓取异常或者.catch抓取异常
 * @update: 2023-11-07 11:42
 * */
import { useInterface } from "@/hooks/useInterface";
import { createMessage, h5InWeChat } from "@/utils/index";
import { wechatPay } from "@/api/order";
import { CacheKey } from "@/utils/config";

const {loading, hideLoading} = useInterface()

// 微信支付的provider
export const WechatProvider = 'wxpay'

// 支付类型（后端用）
export const ServiceFrom = {
    'h5': 'h5', // H5（微信内h5、微信外H5）
    'weixin': 'weixin_applet', // 微信小程序
    'app': 'weixin_app' // 微信APP
}

export const ServicePayType = {
    'h5': 'weixin_h5', // H5（微信内h5、微信外H5）
    'weixin': 'weixin_applet', // 微信小程序
    'app': 'weixin_app' // 微信APP
}



// 支付类型（前端用）
export const PayType = {
    0: 'wechat', // 微信支付
    1: 'balance', // 余额支付
    2: 'alipay', // 支付宝支付
}
// 微信支付环境类型(前端用)
export const WechatPayEnvType = {
    0: 'app', // APP
    1: 'miniProgram', // 小程序
    2: 'h5InWechat', // 微信内H5
    3: 'h5OutWechat' // 微信外H5
}

/**
 * 获取当前环境
 * @returns {*} WechatPayEnvType
 */
export function getEnvType() {
    let envType; // 0.APP 1.微信小程序 2.微信内H5 3.微信外H5 WechatPayEnvType
    // #ifdef APP-PLUS
    envType = WechatPayEnvType["0"]
    // #endif
    // #ifdef MP-WEIXIN
    envType = WechatPayEnvType["1"]
    // #endif
    // #ifdef H5
    if (h5InWeChat()) {
        envType = WechatPayEnvType["2"]
    } else {
        envType = WechatPayEnvType["3"]
    }
    // #endif
    return envType
}

/**
 * @name: 支付
 * @param options {{ type:any, payInfo:any }}
 * type PayType
 * payInfo 结算信息
 */
export async function doPayment(options) {
    loading({title: '支付中...'})
    const res = await _chooseEnvToPayment(options)
    hideLoading()
    return res
}

/**
 * 区别环境调用支付
 * @param options
 * @returns {Promise<{msg: *, data: *}>}
 * @private
 */
async function _chooseEnvToPayment(options) {
    const {type, payInfo} = options
    let res;
    if (type === PayType[0]) {
        // 微信支付
        switch (getEnvType()) {
            case WechatPayEnvType["0"]:
                res = await _appWechatPay(payInfo)
                break;
            case WechatPayEnvType["1"]:
                res = await _miniProgramPay(payInfo)
                break;
            case WechatPayEnvType["2"]:
                res = await _h5InWechatPay(payInfo)
                break;
            case WechatPayEnvType["3"]:
                res = await _h5OutWechatPay(payInfo)
                break;
        }
    }
    if (type === PayType["1"]) {
        // 余额支付
    }
    if (type === PayType["2"]) {
        // 支付宝
        res = await _aliPay(payInfo)
    }
    return res
}

/**
 * APP微信支付
 * @param payInfo
 * @private
 * @docs https://pay.weixin.qq.com/docs/merchant/apis/in-app-payment/app-transfer-payment.html
 */
function _appWechatPay(payInfo) {
    return new Promise(async (resolve, reject) => {
        const payData = {
            from: ServiceFrom['app'],
            paytype: ServicePayType['app'],
            uni: payInfo.orderId
        }
        // 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
        const res = await _doWechatPayRequest(payData)
        // 兼容性写法：防止电脑端用户支付后马上关闭支付弹窗导致失败
        uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(payData))
        const orderInfo = {
            appid: res.appId, // 微信开放平台审核通过的移动应用AppID 。
            prepayid: res.merchant_id, // 请填写商户号mchid对应的值。
            timestamp: res.timeStamp, // 时间
            sign: res.paySign, // 签名，使用字段AppID、timeStamp、nonceStr、prepayid计算得出的签名值 注意：取值RSA格式
            partnerid: res.out_trade_no, // 微信返回的支付交易会话ID，该值有效期为2小时。
            noncestr: res.nonceStr, // 随机字符串，不长于32位。推荐随机数生成算法。
            package: 'Sign=WXPay', // 暂填写固定值Sign=WXPay
        }
        uni.requestPayment({
            provider: WechatProvider,
            orderInfo,
            success: (res) => resolve(createMessage('用户支付成功', res)),
            fail: (error) => reject(createMessage('用户支付失败', error))
        })
    })
}

/**
 * 微信小程序支付
 * @param payInfo
 * @private
 * @docs https://pay.weixin.qq.com/docs/merchant/apis/h5-payment/h5-transfer-payment.html
 */
function _miniProgramPay(payInfo) {
    return new Promise(async (resolve, reject) => {
        const payData = {
            from: ServiceFrom['weixin'],
            paytype: ServiceFrom['weixin'],
            uni: payInfo.orderId
        }
        // 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
        const res = await _doWechatPayRequest(payData)
        // 兼容性写法：防止电脑端用户支付后马上关闭支付弹窗导致失败
        uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(payData))
        uni.requestPayment({
            timeStamp: res.timeStamp,
            nonceStr: res.nonceStr,
            signType: res.signType,
            paySign: res.paySign,
            package: res.package,
            provider: WechatProvider,
            success: (res) => resolve(createMessage('用户支付成功', res)),
            fail: (error) => reject(createMessage('用户支付失败', error))
        })
    })

}

/**
 * 微信内H5支付
 * @param payInfo
 * @private
 * @docs https://pay.weixin.qq.com/docs/merchant/apis/h5-payment/h5-transfer-payment.html
 */
async function _h5InWechatPay(payInfo) {
    return new Promise(async (resolve, reject) => {
        const payData = {
            from: ServiceFrom['h5'],
            paytype: ServicePayType['h5'],
            uni: payInfo.orderId
        }
        // 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
        const res = await _doWechatPayRequest(payData)
        /** 注册JS SDK */
        jweixin.config({
            debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来，若要查看传入的参数，可以在pc端打开，参数信息会通过log打出，仅在pc端时才会打印。
            appId: res.appId, // 必填，公众号的唯一标识
            timestamp: res.timeStamp, // 必填，生成签名的时间戳
            nonceStr: res.nonceStr, // 必填，生成签名的随机串
            signature: res.paySign, // 必填，签名，见附录1
            jsApiList: ['chooseWXPay'] // 必填，需要使用的JS接口列表，所有JS接口列表见附录2
        });
        /** JS SDK 可使用状态 */
        jweixin.ready(() => {
            /** 检查JS SDK API是否可用 */
            jweixin.checkJsApi({
                jsApiList: ['chooseWXPay'], // 需要检测的JS接口列表，所有JS接口列表见附录2,
                success: () => {
                },
                fail: (error) => {
                    return reject(createMessage('微信版本过低，请升级微信版本', error))
                }
            });
            uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(payData))
            /** 去拉起微信支付 */
            jweixin.chooseWXPay({
                timestamp: res.timeStamp, // 支付签名时间戳，注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
                nonceStr: res.nonceStr, // 支付签名随机串，不长于 32 位
                package: res.package, // 统一支付接口返回的prepay_id参数值，提交格式如：prepay_id=***）
                signType: res.signType, // 签名方式，默认为'SHA1'，使用新版支付需传入'MD5'
                paySign: res.paySign, // 支付签名
                success: (res) => {
                    // 支付成功后的回调函数
                    return resolve(createMessage('用户支付成功', res))
                },
                cancel: (r) => {
                    return reject(createMessage('用户取消支付', {}))
                },
                fail: (error) => {
                    return reject(createMessage('跳转微信支付失败', error))
                }
            });
        });
        /** JS SDK发生错误 */
        jweixin.error((error) => {
            return reject(createMessage('JS-SDK加载错误', error))
        });
    })
}


/**
 * 微信外H5支付
 * @param payInfo
 * @private
 */
async function _h5OutWechatPay(payInfo) {
    const payData = {
        from: ServiceFrom['h5'],
        paytype: ServicePayType['h5'],
        uni: payInfo.orderId
    }
    const res = await _doWechatPayRequest(payData)
    if (res && res.mwebUrl) {
        // 缓存支付订单数据
        uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(payData))
        location.replace(res.mwebUrl)
        return Promise.resolve(createMessage('用户支付成功', {type: 'h5'}))
    } else {
        return Promise.reject(createMessage('服务端拉起支付失败', {type: 'h5', error: res}))
    }
}

/**
 * 支付宝支付
 * @param payInfo
 */
function _aliPay(payInfo) {
    return Promise.reject("暂不支持支付宝支付")
}

/**
 * 请求服务端获取支付信息
 * @param data {{from:string, paytype: string, uni: string }}
 * @returns {Promise<*>}
 * @private
 */
async function _doWechatPayRequest(data) {
    return await wechatPay(data)
}
