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

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
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.exception.ChannelException;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.params.IsvParams;
import com.jeequan.jeepay.core.model.params.yspay.YspayIsvsubMchParams;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionService;
import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit;
import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * 分账接口
 *
 * @author xiaoyu
 *
 * @date 2023/8/9 8:45
 */
@Slf4j
@Service
public class YspayDivisionService extends AbstractDivisionService {

    @Autowired private ConfigContextQueryService configContextQueryService;

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

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

    @Override
    public ChannelRetMsg bind(DivisionSubjectEx subjectEx, String isvNo) {
        String logPrefix = "[银盛添加分账]";
        try {
            String newDivisionReceiverSubMchId = subjectEx.getChannelDivisionNo();
            log.info("{}, 接收人账号{}", logPrefix, newDivisionReceiverSubMchId);
            return ChannelRetMsg.confirmSuccess(null).setChannelAttach(newDivisionReceiverSubMchId);
        } catch (ChannelException e) {
            ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
            channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode());
            channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg());
            return channelRetMsg;
        } catch (Exception e) {
            log.error("{}异常", logPrefix, e);
            ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
            channelRetMsg.setChannelErrMsg(e.getMessage());
            return channelRetMsg;
        }
    }

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

        try {
            JSONObject bizContent = new JSONObject();
            // 商户批次号,格式：(S|F)+15位唯一流水，建议格式：S+YYYYMMDD+XXXXXXX.F表示代付，S表示代收。单笔交易可空，批量交易时必写
            // 0-16位
//            bizContent.put("out_batch_no", batchOrderId);
            // 订单号
            bizContent.put("out_trade_no", payOrder.getPayOrderId());
            // 收款商户号
            bizContent.put("payee_usercode", payOrder.getChannelMchNo());
            // 原交易订单金额 20长度位，保留2位小数
            bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt()+""));
            // 原订单是否参与分账 01：是，02否
            bizContent.put("is_divistion", "01");
            // 是否重新分账 Y：是，N：否
            bizContent.put("is_again_division", "Y");
            // 分行模式 01 ：比例，02：金额
            bizContent.put("division_mode", "02");

            JSONArray receivers = new JSONArray();
            BigDecimal totalDivAmt = BigDecimal.ZERO;
            boolean isCheckFee = false;
            for (int i = 0; i < recordList.size(); i++) {
                PayOrderDivisionRecord record = recordList.get(i);
                if(record.getCalDivisionAmount() <= 0){ //金额为 0 不参与分账处理
                    continue;
                }
                if(StringUtils.isEmpty(record.getChannelAccNo())){ // 判断是否都包含渠道号码
                    throw new BizException(record.getAccName() + "账号没有分账渠道号， 本次分账失败");
                }

                JSONObject receiver = new JSONObject();
                receiver.put("division_mer_usercode", record.getChannelAccNo());
                totalDivAmt = totalDivAmt.add(BigDecimal.valueOf(record.getCalDivisionAmount()));
                receiver.put("div_amount", AmountUtil.convertCent2Dollar(record.getCalDivisionAmount()));
                // 由商户收取手续费 是否收取手续费（01：是，02否）
                if (record.getAccType() == 1) {
                    isCheckFee = true;
                    receiver.put("is_chargeFee", "01");
                }else {
                    receiver.put("is_chargeFee", "02");
                }
                receivers.add(receiver);
            }
            //银盛加收款方的处理
            BigDecimal paymentDivAmt = (BigDecimal.valueOf(payOrder.getFindAmt()).subtract(totalDivAmt)).divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_EVEN);
            if(paymentDivAmt.compareTo(BigDecimal.ZERO) > 0){
                JSONObject receiver = new JSONObject();
                receiver.put("division_mer_usercode", payOrder.getChannelMchNo());
                receiver.put("div_amount",paymentDivAmt.toPlainString());
                receiver.put("is_chargeFee",isCheckFee ? "02" : "01");
                receivers.add(receiver);
            }
            if(receivers.isEmpty()){
                return ChannelRetMsg.confirmSuccess(null);
            }
            // 分账对象
            bizContent.put("div_list", receivers);
            // 发起分账请求
            String result = YspayKit.divisionRequest(YspayKit.DIVISION_URL, "ysepay.single.division.online.accept", mchAppConfigContext.getMchApplyment().getIsvNo(), bizContent, getNotifyUrl(), payOrder.getIfCode());
            JSONObject resJson = JSONObject.parseObject(result);
            JSONObject response = resJson.getJSONObject("ysepay_single_division_online_accept_response");
            String code = response.getString("code");
            log.info("【银盛分账】订单号：{}，分账返回结果:{}", payOrder.getPayOrderId(),response);
            if (YspayKit.RES_CODE.equals(code)) {
                String returnCode = response.getString("returnCode");
                // 分账受理中
                if("0000".equals(returnCode)){
                    ChannelRetMsg waiting = ChannelRetMsg.waiting();
                    waiting.setChannelErrMsg(response.getString("retrunInfo"));
                    return waiting;
                }
            }
            // 失败
            return ChannelRetMsg.confirmFail().setChannelErrCode(response.getString("code")).setChannelErrMsg(JSON.toJSONString(response));

        } catch (ChannelException e) {

            ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
            channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode());
            channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg());
            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) {
        String logPrefix = "【银盛分账回退】";

        try {
            YspayIsvsubMchParams mchParams = (YspayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), payOrderDivisionRecord.getIfCode());
            JSONObject bizContent = new JSONObject();

            // 商户原交易订单号
            bizContent.put("out_trade_no", payOrderDivisionRecord.getPayOrderId());
            // 商户系统的交易发生日期格式yyyyMMdd 示例值：20180525
            bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN));
            // 银盛原交易流水号
            bizContent.put("trade_no", payOrder.getChannelOrderNo());
            // 需要退款的金额，该金额不能大于订单金额,单位为元，支持两位小数，Number(10,2)指10位长度，2位精度
            bizContent.put("refund_amount", AmountUtil.convertCent2Dollar(payOrderDivisionRefundRecord.getDivisionRefundAmount()+""));
            // 退款的原因说明，该参数最长为50个汉字。
            bizContent.put("refund_reason", "分账退款");
            // 标商户系统生成的退款订单号，标识一次退款请求，同一笔交易多次退款需要保证唯一。
            bizContent.put("out_request_no", payOrderDivisionRefundRecord.getDivisionRefundId());
            // 原交易是否参与分账（01或空代表是，02代表否）
            bizContent.put("is_division", "01");
            // 原交易分账模式（01：比例，02：金额）
            bizContent.put("ori_division_mode", "02");

            JSONArray refundSplitInfo = new JSONArray();
            JSONObject refundJson = new JSONObject();
            refundJson.put("refund_mer_id", payOrderDivisionRecord.getChannelAccNo());
            refundJson.put("refund_amount", AmountUtil.convertCent2Dollar(payOrderDivisionRefundRecord.getDivisionRefundAmount()));
            refundJson.put("ori_division_mode", "02");
            refundSplitInfo.add(refundJson);

            JSONArray orderDivList = new JSONArray();
            JSONObject orderDivJson = new JSONObject();
            orderDivJson.put("division_mer_id", payOrderDivisionRecord.getChannelAccNo());
            orderDivJson.put("division_amount", AmountUtil.convertCent2Dollar(payOrderDivisionRefundRecord.getDivisionRefundAmount()));
            orderDivJson.put("is_charge_fee", "02");
            orderDivList.add(orderDivJson);

            bizContent.put("refund_split_info", refundSplitInfo);
            bizContent.put("order_div_list", orderDivList);

            String result = YspayKit.divisionRequest(YspayKit.DIVISION_REFUND_URL, "ysepay.online.trade.refund.split", mchAppConfigContext.getMchApplyment().getIsvNo(), bizContent, null, payOrder.getIfCode());
            JSONObject resJson = JSONObject.parseObject(result);
            JSONObject response = resJson.getJSONObject("ysepay_online_trade_refund_split_response");
            String code = response.getString("code");
            if (YspayKit.RES_CODE.equals(code)) {
                return ChannelRetMsg.confirmSuccess(response.getString("trade_no"));
            }else {
                ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
                channelRetMsg.setChannelErrCode(code);
                channelRetMsg.setChannelErrMsg(response.getString("msg"));
                return channelRetMsg;
            }

        } catch (Exception e) {
            throw new BizException(e.getMessage());
        }
    }

    @Override
    public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) {
        String logPrefix = "【银盛分账余额查询】";
        try {
            Long balanceAmt = 0L;
            return balanceAmt;
        } catch (Exception e) {
            throw new BizException(e.getMessage());
        }
    }

    @Override
    public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) {
        String logPrefix = "银盛分账账号提现";
        try {
            return ChannelRetMsg.waiting();
        } catch (Exception e) {
            throw new BizException(e.getMessage());
        }
    }

}
