package com.jeequan.jeepay.thirdparty.channel.wxpay;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.profitsharing.*;
import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReceiver;
import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingUnfreezeRequest;
import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingUnfreezeResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.*;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionService;
import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit;
import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper;
import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
* 分账接口： 微信官方
*
* @author terrfly
*
* @date 2021/8/22 09:05
*/
@Slf4j
@Service
public class WxpayDivisionService extends AbstractDivisionService {

    @Autowired private ConfigContextQueryService configContextQueryService;

    @Override
    public String getIfCode() {
        return CS.IF_CODE.WXPAY;
    }

    @Override
    public boolean isSupport() {
        return false;
    }

    @Override
    public ChannelRetMsg bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) {

        try {

            WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);

            if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) {  //V2
                ProfitSharingReceiverRequest request = new ProfitSharingReceiverRequest();

                //放置isv信息
                WxpayKit.putApiIsvInfo(mchAppConfigContext, request);

                JSONObject receiverJSON = new JSONObject();

                // 0-个人， 1-商户  (目前仅支持服务商appI获取个人openId, 即： PERSONAL_OPENID， 不支持 PERSONAL_SUB_OPENID )
                receiverJSON.put("type", mchDivisionReceiver.getAccType() == 0 ? "PERSONAL_OPENID" : "MERCHANT_ID");
                receiverJSON.put("account", mchDivisionReceiver.getAccNo());
                receiverJSON.put("name", mchDivisionReceiver.getAccName());
                receiverJSON.put("relation_type", mchDivisionReceiver.getRelationType());
                receiverJSON.put("custom_relation", mchDivisionReceiver.getRelationTypeName());
                request.setReceiver(receiverJSON.toJSONString());

                ProfitSharingReceiverResult profitSharingReceiverResult =
                        wxServiceWrapper.getWxPayService().getProfitSharingService().addReceiver(request);

                // 明确成功
                return ChannelRetMsg.confirmSuccess(null);
            }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) {

                ProfitSharingReceiver profitSharingReceiver = new ProfitSharingReceiver();

                profitSharingReceiver.setType(mchDivisionReceiver.getAccType() == 0 ? "PERSONAL_OPENID" : "MERCHANT_ID");
                profitSharingReceiver.setAccount(mchDivisionReceiver.getAccNo());
                profitSharingReceiver.setName(mchDivisionReceiver.getAccName());
                profitSharingReceiver.setRelationType(mchDivisionReceiver.getRelationType());
                profitSharingReceiver.setCustomRelation(mchDivisionReceiver.getRelationTypeName());

                profitSharingReceiver.setAppid(WxpayKit.getWxPayConfig(wxServiceWrapper).getAppId());

                // 特约商户
                if(mchAppConfigContext.isIsvsubMch()){
                    WxpayIsvsubMchParams isvsubMchParams =
                            (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY);

                    profitSharingReceiver.setSubMchId(isvsubMchParams.getSubMchId());
                }

                ProfitSharingReceiver receiver = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().addProfitSharingReceiver(profitSharingReceiver);

                // 明确成功
                return ChannelRetMsg.confirmSuccess(null);
            } else {
                return ChannelRetMsg.sysError("请选择微信V2或V3模式");
            }

        } catch (WxPayException wxPayException) {
            ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
            WxpayKit.commonSetErrInfo(channelRetMsg, wxPayException);
            return channelRetMsg;

        } catch (Exception e) {

            log.error("请求微信绑定分账接口异常！", e);
            ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
            channelRetMsg.setChannelErrMsg("系统异常：" + e.getMessage());
            return channelRetMsg;
        }
    }

    @Override
    public ChannelRetMsg singleDivision(PayOrder payOrder, List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext) {

        try {

            WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);

            if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) {  //V2
                ProfitSharingRequest request = new ProfitSharingRequest();
                request.setTransactionId(payOrder.getChannelOrderNo());

                //放置isv信息
                WxpayKit.putApiIsvInfo(mchAppConfigContext, request);

                if(recordList.isEmpty()){
                    request.setOutOrderNo(SeqKit.genDivisionBatchId()); // 随机生成一个订单号
                }else{
                    request.setOutOrderNo(recordList.get(0).getBatchOrderId()); //取到批次号
                }

                JSONArray receiverJSONArray = new JSONArray();

                for (int i = 0; i < recordList.size(); i++) {

                    PayOrderDivisionRecord record = recordList.get(i);
                    if(record.getCalDivisionAmount() <= 0){
                        continue;
                    }

                    JSONObject receiverJSON = new JSONObject();
                    // 0-个人， 1-商户  (目前仅支持服务商appI获取个人openId, 即： PERSONAL_OPENID， 不支持 PERSONAL_SUB_OPENID )
                    receiverJSON.put("type", record.getAccType() == 0 ? "PERSONAL_OPENID" : "MERCHANT_ID");
                    receiverJSON.put("account", record.getAccNo());
                    receiverJSON.put("amount", record.getCalDivisionAmount());
                    receiverJSON.put("description", record.getPayOrderId() + "分账");
                    receiverJSONArray.add(receiverJSON);
                }

                //不存在接收账号时，订单完结（解除冻结金额）
                if(receiverJSONArray.isEmpty()){
                    return ChannelRetMsg.confirmSuccess(this.divisionFinish(payOrder, mchAppConfigContext));
                }

                request.setReceivers(receiverJSONArray.toJSONString());

                ProfitSharingResult profitSharingResult = wxServiceWrapper.getWxPayService().getProfitSharingService().profitSharing(request);
                return ChannelRetMsg.confirmSuccess(profitSharingResult.getOrderId());

            }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) {

                com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingRequest request = new com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingRequest();
                request.setTransactionId(payOrder.getChannelOrderNo());
                request.setUnfreezeUnsplit(true); // 分账完成 解冻金额

                request.setAppid(WxpayKit.getWxPayConfig(wxServiceWrapper).getAppId());
                // 特约商户
                if(mchAppConfigContext.isIsvsubMch()){
                    WxpayIsvsubMchParams isvsubMchParams =
                            (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY);

                    request.setSubMchId(isvsubMchParams.getSubMchId());
                }

                if(recordList.isEmpty()){
                    request.setOutOrderNo(SeqKit.genDivisionBatchId()); // 随机生成一个订单号
                }else{
                    request.setOutOrderNo(recordList.get(0).getBatchOrderId()); //取到批次号
                }

                List<ProfitSharingReceiver> receivers = new ArrayList<>();
                for (int i = 0; i < recordList.size(); i++) {

                    PayOrderDivisionRecord record = recordList.get(i);
                    if(record.getCalDivisionAmount() <= 0){
                        continue;
                    }

                    ProfitSharingReceiver receiver = new ProfitSharingReceiver();
                    // 0-个人， 1-商户  (目前仅支持服务商appI获取个人openId, 即： PERSONAL_OPENID， 不支持 PERSONAL_SUB_OPENID )
                    receiver.setType(record.getAccType() == 0 ? "PERSONAL_OPENID" : "MERCHANT_ID");
                    receiver.setAccount(record.getAccNo());
                    receiver.setAmount(record.getCalDivisionAmount());
                    receiver.setDescription(record.getPayOrderId() + "分账");
                    receivers.add(receiver);
                }
                //不存在接收账号时，订单完结（解除冻结金额）
                if(receivers.isEmpty()){
                    return ChannelRetMsg.confirmSuccess(this.divisionFinish(payOrder, mchAppConfigContext));
                }
                request.setReceivers(receivers);

                com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingResult profitSharingResult = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().profitSharing(request);
                return ChannelRetMsg.confirmSuccess(profitSharingResult.getOrderId());
            } else {
                return ChannelRetMsg.sysError("请选择微信V2或V3模式");
            }

        } catch (WxPayException wxPayException) {

            ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
            WxpayKit.commonSetErrInfo(channelRetMsg, wxPayException);
            return channelRetMsg;

        } catch (Exception e) {
            log.error("微信分账失败", e);
            ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
            channelRetMsg.setChannelErrMsg(e.getMessage());
            return channelRetMsg;
        }
    }

    @Override
    public ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) {

        try{

            WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);

            if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) {  //V2

                ProfitSharingReturnRequest request = new ProfitSharingReturnRequest();

                //放置isv信息
                WxpayKit.putApiIsvInfo(mchAppConfigContext, request);
                request.setOutOrderNo(payOrderDivisionRecord.getBatchOrderId()); // 原发起分账请求时使用的商户后台系统的分账单号。
                request.setOutReturnNo(payOrderDivisionRefundRecord.getDivisionRefundId()); //商户回退单号
                request.setReturnAccountType("MERCHANT_ID"); // 暂时只支持商户接收方回退
                request.setReturnAccount(payOrderDivisionRecord.getAccNo());
                request.setReturnAmount(payOrderDivisionRefundRecord.getDivisionRefundAmount().intValue()); //金额
                request.setDescription(payOrderDivisionRefundRecord.getPayOrderId() + "退款");

                ProfitSharingReturnResult profitSharingReturnResult =
                        wxServiceWrapper.getWxPayService().getProfitSharingService().profitSharingReturn(request);

                // 明确成功
                return ChannelRetMsg.confirmSuccess(profitSharingReturnResult.getReturnNo());

            }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) {

                com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReturnRequest request = new com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReturnRequest();
                // 特约商户
                if(mchAppConfigContext.isIsvsubMch()){
                    WxpayIsvsubMchParams isvsubMchParams =
                            (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY);

                    request.setSubMchId(isvsubMchParams.getSubMchId());
                }

                request.setOutOrderNo(payOrderDivisionRecord.getBatchOrderId());
                request.setOutReturnNo(payOrderDivisionRefundRecord.getDivisionRefundId());
                request.setReturnMchid(payOrderDivisionRecord.getAccNo());
                request.setAmount(payOrderDivisionRefundRecord.getDivisionRefundAmount());
                request.setDescription(payOrderDivisionRefundRecord.getPayOrderId() + "退款");
                com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReturnResult profitSharingReturnResult = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().profitSharingReturn(request);

                // 明确成功
                return ChannelRetMsg.confirmSuccess(profitSharingReturnResult.getReturnId());

            } else {
                return ChannelRetMsg.sysError("请选择微信V2或V3模式");
            }

        } catch (WxPayException wxPayException) {
            ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
            WxpayKit.commonSetErrInfo(channelRetMsg, wxPayException);
            return channelRetMsg;

        } catch (Exception e) {

            log.error("请求微信分账回退接口异常！", e);
            ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
            channelRetMsg.setChannelErrMsg("系统异常：" + e.getMessage());
            return channelRetMsg;
        }

    }


    /** 调用订单的完结接口 (分账对象不存在时) */
    private String divisionFinish(PayOrder payOrder,MchAppConfigContext mchAppConfigContext) throws WxPayException {

        WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);

        if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) {  //V2

            ProfitSharingFinishRequest request = new ProfitSharingFinishRequest();

            //放置isv信息
            WxpayKit.putApiIsvInfo(mchAppConfigContext, request);

            request.setSubAppId(null); // 传入subAppId 将导致签名失败

            request.setTransactionId(payOrder.getChannelOrderNo());
            request.setOutOrderNo(SeqKit.genDivisionBatchId());
            request.setDescription("完结分账");

            return wxServiceWrapper.getWxPayService().getProfitSharingService().profitSharingFinish(request).getOrderId();
        }else {

            ProfitSharingUnfreezeRequest request = new ProfitSharingUnfreezeRequest();
            // 特约商户
            if(mchAppConfigContext.isIsvsubMch()){
                WxpayIsvsubMchParams isvsubMchParams =
                        (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY);

                request.setSubMchId(isvsubMchParams.getSubMchId());
            }

            request.setTransactionId(payOrder.getChannelOrderNo());
            request.setOutOrderNo(SeqKit.genDivisionBatchId());
            request.setDescription("完结分账");
            ProfitSharingUnfreezeResult profitSharingUnfreezeResult = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().profitSharingUnfreeze(request);

            // 明确成功
            return profitSharingUnfreezeResult.getOrderId();
        }
    }

    /** 调用订单的完结接口 (分账已完成) */
    @Override
    public String divisionFinishAfterDivision(PayOrderDivisionRecord divisionRecord, MchAppConfigContext mchAppConfigContext) {

        try {
            WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);

            if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) {  //V2
                return null;
            }else {

                ProfitSharingUnfreezeRequest request = new ProfitSharingUnfreezeRequest();
                // 特约商户
                if(mchAppConfigContext.isIsvsubMch()){
                    WxpayIsvsubMchParams isvsubMchParams =
                            (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY);

                    request.setSubMchId(isvsubMchParams.getSubMchId());
                }

                request.setTransactionId(divisionRecord.getPayOrderChannelOrderNo());
                request.setOutOrderNo(divisionRecord.getBatchOrderId());

                request.setDescription("完结分账");
                ProfitSharingUnfreezeResult profitSharingUnfreezeResult = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().profitSharingUnfreeze(request);

                // 明确成功
                return profitSharingUnfreezeResult.getOrderId();
            }
        }catch (WxPayException e) {
            log.error("分账完成，调用完结分账失败：", e);
            return null;
        }
    }

    @Override
    public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) {
        throw new BizException("接口不支持");
    }

    @Override
    public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) {
        throw new BizException("接口不支持");
    }

}
