package com.jeequan.jeepay.member.ctrl.member;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.ApiField;
import com.jeequan.jeepay.JeepayClient;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBApplicationConfig;
import com.jeequan.jeepay.core.model.QRCodeParams;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.core.utils.JsonKit;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.exception.JeepayException;
import com.jeequan.jeepay.member.ctrl.CommonCtrl;
import com.jeequan.jeepay.model.DeviceInfo;
import com.jeequan.jeepay.model.JeepayObject;
import com.jeequan.jeepay.model.PayOrderCreateResModel;
import com.jeequan.jeepay.request.PayOrderCreateRequest;
import com.jeequan.jeepay.response.PayOrderCreateResponse;
import com.jeequan.jeepay.service.impl.*;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* 会员充值  服务入口controller
*
* @author zx
* @date 2023/4/12 17:27
*/
@RestController
@RequestMapping("/api/member/recharge")
public class MemberRechargeController extends CommonCtrl {

    @Autowired private MemberInfoService memberInfoService;
    @Autowired private MchAppService mchAppService;
    @Autowired private MemberRechargeRuleService memberRechargeRuleService;
    @Autowired private MemberRechargeRecordService memberRechargeRecordService;
    @Autowired private MchConfigService mchConfigService;
    @Autowired private MchApplymentService mchApplymentService;

    /**
     * 会员充值
     **/
    @PostMapping
    public ApiRes recharge() {

        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();

        // 获取商户配置信息
        MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, false);
        if(mchAppConfigContext == null){
            throw new BizException("商户或商户应用不存在");
        }
        if(mchAppConfigContext.getMchInfo() == null || mchAppConfigContext.getMchInfo().getState() != CS.YES){
            throw new BizException("商户信息不存在或商户状态不可用");
        }

        // 查询会员信息
        MemberInfo memberInfo = memberInfoService.selectOne(mchAppConfigContext.getMchNo(), getCurrentMbrId());
        if (memberInfo == null || memberInfo.getState() != CS.YES) {
            return ApiRes.customFail("会员不存在或已禁用");
        }

        // 充值金额，前端传 充值规则ID，则以此ID为准；不传充值规则ID，则充值为自定义金额且必填
        String rechargeRuleId = getValString("rechargeRuleId");
        Long payAmount = 0L; // 实际支付金额
        Long giveAmount = 0L; // 赠送金额
        if (StringUtils.isNotBlank(rechargeRuleId)) {
            MemberRechargeRule rechargeRule = memberRechargeRuleService.getById(rechargeRuleId);
            if (rechargeRule == null || !mchAppConfigContext.getMchNo().equals(rechargeRule.getMchNo()) || rechargeRule.getState() != CS.YES) {
                throw new BizException("充值赠送规则不存在或已禁用");
            }
            payAmount = rechargeRule.getRechargeAmount();
            if (rechargeRule.getGiveAmount() != null) {
                giveAmount = rechargeRule.getGiveAmount();
            }
        }else {
            payAmount = getRequiredAmountL("rechargeAmount");
        }
        if (payAmount <= 0) {
            throw new BizException("充值金额错误！");
        }

        // 校验商户最大储值金额
        Long memebrMaxbalance = null;
        String val = mchConfigService.getConfigValByMchNoAndKey(memberInfo.getMchNo(), MchConfig.SELF_MEMBER_MAX_BALANCE);
        if (StringUtils.isNotBlank(val) && NumberUtil.isLong(val)) {
            memebrMaxbalance = Long.parseLong(val);
        }
        if (memebrMaxbalance == null || memebrMaxbalance.equals(0L)) {
            memebrMaxbalance = sysConfigService.getDBDefaultConfig().getMchMbrMaxBalance();
        }
        if (memebrMaxbalance != null && !memebrMaxbalance.equals(0L)) {
            Long totalBalance = memberInfoService.selectTotalBalance(MemberInfo.gw().eq(MemberInfo::getMchNo, memberInfo.getMchNo()));
            if (memebrMaxbalance < totalBalance + payAmount + giveAmount) {
                throw new BizException("已超商家充值总余额上限！");
            }
        }

        MemberRechargeRecord rechargeRecord = initMemberRechargeRecord(qrCodeParams, memberInfo, payAmount, giveAmount, getValString("remark"));
        return doPay(rechargeRecord, qrCodeParams, memberInfo);
    }

    private ApiRes doPay(MemberRechargeRecord rechargeRecord, QRCodeParams qrCodeParams, MemberInfo memberInfo)  {

        // 会员充值仅支持码牌模式
        MchQrcodeCard mchQrcodeCard = mchQrcodeCardService.getById(qrCodeParams.getId());

        PayOrderCreateRequest orderCreateRequest = new PayOrderCreateRequest();
        PayOrderCreateReqModelAddStoreId model = new PayOrderCreateReqModelAddStoreId();
        model.setPas(SysConfigService.PLATFORM_API_SECRET); // 通信秘钥
        orderCreateRequest.setBizModel(model);

        model.setWayCode(rechargeRecord.getWayCode());
        if (CS.PAY_WAY_CODE_TYPE.WECHAT.equals(rechargeRecord.getWayCodeType())) {
            if(qrCodeParams.getPageType().equals(QRCodeParams.PAGE_TYPE_WECHAT_H5) ){
                model.setChannelExtra(JsonKit.newJson("openid", memberInfo.getWxMpOpenId()).toJSONString()); // 微信公众号openid
            }else if(qrCodeParams.getPageType().equals(QRCodeParams.PAGE_TYPE_WECHAT_LITE) ){
                model.setChannelExtra(JsonKit.newJson("openid", memberInfo.getWxLiteOpenId()).toJSONString()); // 微信小程序openid
            }

        }else if (CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(rechargeRecord.getWayCodeType())) {
            model.setChannelExtra(JsonKit.newJson("buyerUserId", memberInfo.getAliUserId()).toJSONString()); // 支付宝buyerUserId
        }else if (CS.PAY_WAY_CODE_TYPE.YSFPAY.equals(rechargeRecord.getWayCodeType())) {
            model.setChannelExtra(JsonKit.newJson("userId", memberInfo.getYsfUserId()).toJSONString()); // 云闪付userId
        }

        MchAppEntity mchAppEntity = mchAppService.getById(mchQrcodeCard.getAppId()); // 商户应用

        model.setStoreId(mchQrcodeCard.getStoreId()); // 门店ID
        model.setMchNo(rechargeRecord.getMchNo()); // 商户号
        model.setAppId(mchAppEntity.getAppId());
        model.setMchOrderNo(rechargeRecord.getRechargeRecordId()); // 商户号 <---> 充值记录ID
        model.setQrcId(qrCodeParams.getId()); // 码牌ID
        model.setAmount(rechargeRecord.getPayAmount()); // 充值记录 实际支付金额
        model.setCurrency("CNY");
        model.setClientIp(getClientIp());
        model.setSubject("[" + rechargeRecord.getMchNo() + "商户会员充值]");
        model.setBody("[" + rechargeRecord.getMchNo() + "商户会员充值]");
        model.setBuyerRemark(rechargeRecord.getRemark()); // 买家备注
        model.setNotifyUrl(rechargeRecord.getNotifyUrl()); //回调地址
        model.setReturnUrl(rechargeRecord.getReturnUrl()); //同步跳转地址
        model.setMbrId(memberInfo.getMbrId()); // 会员ID
        model.setMbrTel(memberInfo.getMbrTel()); // 会员手机号


        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setDeviceNo(qrCodeParams.getId()); // 订单的qrcId
        deviceInfo.setDeviceType(PayOrder.DEVICE_TYPE_QR_CODE);

        DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
        JeepayClient jeepayClient = new JeepayClient(dbApplicationConfig.getPaySiteUrl(), mchAppEntity.getAppSecret());

        try {
            // 发起支付
            PayOrderCreateResponse response = jeepayClient.execute(orderCreateRequest);

            // 明确失败
            if(!response.isSuccess(mchAppEntity.getAppSecret())){
                // 更新充值订单为充值失败
                String errCode = response.getCode() == 0 ? response.get().getErrCode() : String.valueOf(response.getCode());
                String erMsg = response.getCode() == 0 ? response.get().getErrMsg() : response.getMsg();
                boolean result = memberRechargeRecordService.updateInit2Fail(rechargeRecord.getRechargeRecordId(), errCode, erMsg);
                if(!result){
                    throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
                }
                return ApiRes.customFail(erMsg);
            }

            // 更新充值订单为充值中
            PayOrderCreateResModel orderInfo = response.get();
            boolean result = memberRechargeRecordService.updateInit2Ing(rechargeRecord.getRechargeRecordId(), orderInfo.getPayOrderId());
            if(!result){
                throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
            }

            JSONObject resultJSON = (JSONObject) JSONObject.toJSON(orderInfo);
            resultJSON.put("payAmount", AmountUtil.convertCent2Dollar(rechargeRecord.getPayAmount()));

            return ApiRes.ok(resultJSON);
        } catch (JeepayException e) {
            throw new BizException(e.getMessage());
        }
    }


    private MemberRechargeRecord initMemberRechargeRecord(QRCodeParams qrCodeParams, MemberInfo memberInfo, Long payAmount, Long giveAmount, String remark) {
        MchQrcodeCard mchQrcodeCard = mchQrcodeCardService.getById(qrCodeParams.getId());

        MemberRechargeRecord rechargeRecord = new MemberRechargeRecord();
        rechargeRecord.setRechargeRecordId(SeqKit.genMhoOrderId()); // 商户单号
        rechargeRecord.setMbrId(memberInfo.getMbrId());
        rechargeRecord.setMbrName(memberInfo.getMbrName());
        rechargeRecord.setMbrTel(memberInfo.getMbrTel());
        rechargeRecord.setMchNo(memberInfo.getMchNo());
        rechargeRecord.setPayAmount(payAmount); // 支付金额
        rechargeRecord.setGiveAmount(giveAmount);
        rechargeRecord.setEntryAmount(payAmount + defaultLong(giveAmount)); // 账户入账金额
        rechargeRecord.setState(MemberRechargeRecord.STATE_INIT);

        covertWayCode(qrCodeParams, rechargeRecord);
        MchApplyment applyment = mchApplymentService.getById(mchQrcodeCard.getMchApplyId());
        DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
        rechargeRecord.setReturnUrl(dbApplicationConfig.genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, mchQrcodeCard.getEntryPage(), mchQrcodeCard.getQrcId() + "", applyment.getIsvNo())); //同步跳转地址
        rechargeRecord.setNotifyUrl(dbApplicationConfig.getMemberSiteUrl() + "/api/anon/notify/memberRecharge"); //回调地址
        rechargeRecord.setRemark(remark);

        boolean result = memberRechargeRecordService.save(rechargeRecord);
        if (!result) {
            throw new BizException("充值失败");
        }
        return rechargeRecord;
    }

    /** 转换支付方式 */
    private void covertWayCode(QRCodeParams qrCodeParams, MemberRechargeRecord rechargeRecord){

        // 是否商户自己的小程序调起的
        Byte isUseSubmchAccount = getValByteDefault("isUseSubmchAccount", CS.NO);

        // 获取到当前页面类型
        String currentPageType = qrCodeParams.getPageType();

        // 支付宝内 && 自行创建二维码
        if(QRCodeParams.PAGE_TYPE_ALIPAY_H5.equals(currentPageType) && qrCodeParams.getType() == QRCodeParams.TYPE_QRC){
            MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());
            if(CS.PAY_WAY_CODE.ALI_WAP.equals(mchQrCode.getAlipayWayCode())){ //wap支付， 无需获取
                throw new BizException("支付宝wap或自行创建二维码不支持此功能");
            }
        }

        if(currentPageType.equals(QRCodeParams.PAGE_TYPE_ALIPAY_H5) ){
            rechargeRecord.setWayCode(CS.PAY_WAY_CODE.ALI_JSAPI);
            rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.ALIPAY);

        }else if( currentPageType.equals(QRCodeParams.PAGE_TYPE_ALIPAY_LITE)) {
            rechargeRecord.setWayCode(CS.PAY_WAY_CODE.ALI_LITE);
            rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.ALIPAY);

        }else if(currentPageType.equals(QRCodeParams.PAGE_TYPE_WECHAT_H5) ){
            rechargeRecord.setWayCode(CS.PAY_WAY_CODE.WX_JSAPI);
            rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT);

        }else if(currentPageType.equals(QRCodeParams.PAGE_TYPE_WECHAT_LITE) ){
            rechargeRecord.setWayCode(CS.PAY_WAY_CODE.WX_LITE);
            rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT);

        }else if(currentPageType.equals(QRCodeParams.PAGE_TYPE_YSFPAY_H5) ){
            rechargeRecord.setWayCode(CS.PAY_WAY_CODE.YSF_JSAPI);
            rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.YSFPAY);

        }else {
            throw new BizException("不支持的客户端");
        }

    }

    private Long defaultLong(Long amount) {
        if (amount == null) {
            return 0L;
        }
        return amount;
    }


    /** 与阿里云sdk一样，  直接extends PayOrderCreateReqModel无法传入到接口中对应的参数。 需要把所有的参数放进来。。。   = = 。   **/
    @Data
    public static class PayOrderCreateReqModelAddStoreId extends JeepayObject {

        @ApiField("pas")
        private String pas;

        @ApiField("storeId")
        private String storeId;
        @ApiField("qrcId")
        private String qrcId;

        private static final long serialVersionUID = -3998573128290306948L;

        @ApiField("mchNo")
        private String mchNo;      // 商户号
        @ApiField("appId")
        private String appId;      // 应用ID
        @ApiField("mchOrderNo")
        String mchOrderNo;          // 商户订单号
        @ApiField("wayCode")
        String wayCode;             // 支付方式
        @ApiField("amount")
        Long amount;                // 支付金额
        @ApiField("currency")
        String currency;            // 货币代码，当前只支持cny
        @ApiField("clientIp")
        String clientIp;            // 客户端IP
        @ApiField("subject")
        String subject;             // 商品标题
        @ApiField("body")
        String body;                // 商品描述
        @ApiField("channelBizData")
        String channelBizData;  // 渠道业务参数
        @ApiField("notifyUrl")
        String notifyUrl;           // 异步通知地址
        @ApiField("returnUrl")
        String returnUrl;           // 跳转通知地址
        @ApiField("expiredTime")
        String expiredTime;         // 订单失效时间
        @ApiField("channelExtra")
        String channelExtra;        // 特定渠道额外支付参数
        @ApiField("extParam")
        String extParam;            // 商户扩展参数
        @ApiField("divisionMode")
        private Byte divisionMode;   // 分账模式： 0-该笔订单不允许分账[默认], 1-支付成功按配置自动完成分账, 2-商户手动分账(解冻商户金额)
        @ApiField("sellerRemark")
        String sellerRemark;            // 卖家备注
        @ApiField("buyerRemark")
        String buyerRemark;            // 买家备注
        @ApiField("deviceInfo")
        private DeviceInfo deviceInfo;   // 设备信息
        @ApiField("mbrId")
        private String mbrId;            // 会员ID
        @ApiField("mbrTel")
        private String mbrTel;            // 会员手机号

    }

}
