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

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.entity.MchApplyment;
import com.jeequan.jeepay.core.entity.MchModifyApplyment;
import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService;
import com.jeequan.jeepay.core.model.applyment.Lklsb2bpayApplymentInfo;
import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel;
import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams;
import com.jeequan.jeepay.service.impl.SysConfigService;
import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.LklTkReqMethod;
import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.util.Lklsb2bpayConst;
import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class Lklsb2bpayIsvmchModifyApplymentService implements IIsvmchModifyApplymentService {

    @Autowired
    protected SysConfigService sysConfigService;

    @Autowired
    private ConfigContextQueryService configContextQueryService;

    @Override
    public MutablePair<MchModifyApplyment, MchApplyment> localModifyBase(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        MchModifyApplyment resultModifyApplyment = new MchModifyApplyment();
        MchApplyment resultMchApplyment = new MchApplyment();

        MchModifyApplyment mchModifyApplyment = mchDataPair.getKey();
        resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId());
        resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS);
        MchApplyment mchApplyment = mchDataPair.getValue();
        resultMchApplyment.setApplyId(mchApplyment.getApplyId());

        String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo();
        MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class);

        String originApplyDetailInfo = mchApplyment.getApplyDetailInfo();
        Lklsb2bpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, Lklsb2bpayApplymentInfo.class);
        resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData));

        originMchModifyData.setMchShortName(mchModifyData.getMchShortName());
        resultMchApplyment.setMchShortName(mchModifyData.getMchShortName());

        return new MutablePair<>(resultModifyApplyment, resultMchApplyment);
    }

    @Override
    public MutablePair<MchModifyApplyment, MchApplyment> localModifySettlement(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        MchModifyApplyment resultModifyApplyment = new MchModifyApplyment();
        MchApplyment resultMchApplyment = new MchApplyment();

        MchModifyApplyment mchModifyApplyment = mchDataPair.getKey();
        resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId());
        resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS);
        MchApplyment mchApplyment = mchDataPair.getValue();
        resultMchApplyment.setApplyId(mchApplyment.getApplyId());

        String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo();
        MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class);

        String originApplyDetailInfo = mchApplyment.getApplyDetailInfo();
        Lklsb2bpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, Lklsb2bpayApplymentInfo.class);
        resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData));

        originMchModifyData.setSettAccountType(mchModifyData.getSettAccountType());
        originMchModifyData.setIsLegalInfo("1".equals(mchModifyData.getIllegal()) ? "N" : "Y");
        originMchModifyData.setSettAccountLicenseImg(mchModifyData.getSettAccountLicenseImg());
        originMchModifyData.setSettAccountName(mchModifyData.getSettAccountName());
        originMchModifyData.setSettAccountNo(mchModifyData.getSettAccountNo());
        originMchModifyData.setSettAccountBankName(mchModifyData.getSettAccountBankName());
        originMchModifyData.setLetterOfAuthorizationImg(mchModifyData.getNonLegSettleAuthPic());
        originMchModifyData.setSettAccountIdcardNo(mchModifyData.getSettAccountIdcardNo());
        originMchModifyData.setSettAccountIdcard1Img(mchModifyData.getSettAccountIdcard1Img());
        originMchModifyData.setSettAccountIdcard2Img(mchModifyData.getSettAccountIdcard2Img());
        originMchModifyData.setSettAccountIdcardEffectBegin(mchModifyData.getSettAccountIdcardEffectBegin());
        originMchModifyData.setSettAccountIdcardEffectEnd(mchModifyData.getSettAccountIdcardEffectEnd());

        return new MutablePair<>(resultModifyApplyment, resultMchApplyment);
    }

    @Override
    public MutablePair<MchModifyApplyment, MchApplyment> localModifyRate(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        return null;
    }

    @Override
    public MutablePair<MchModifyApplyment, MchApplyment> localModifySettlementType(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        String applyDetailInfo = mchDataPair.left.getApplyDetailInfo();
        MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class);
        mchDataPair.left.setState(MchApplyment.STATE_SUCCESS_INEFFECTIVE);
        return mchDataPair;
    }

    @Override
    public MutablePair<MchModifyApplyment, MchApplyment> syncChannelModifyBase(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        MchModifyApplyment resultModifyApplyment = new MchModifyApplyment();

        MchModifyApplyment mchModifyApplyment = mchDataPair.getKey();
        resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId());
        resultModifyApplyment.setState(MchApplyment.STATE_AUDITING);
        MchApplyment mchApplyment = mchDataPair.getValue();

        Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment));

        String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo();
        MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class);

        JSONObject param = new JSONObject();
        param.put(Lklsb2bpayConst.CUSTOMER_NO, mchApplyment.getChannelApplyNo());
        param.put("merBizName", mchModifyData.getMchShortName());
        // 其他属性暂不考虑

        try {
            JSONObject applyResp = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.BASE_INFO_CHANGE, isvParams, param);
            Long reviewRelatedId = applyResp.getLong(Lklsb2bpayConst.REVIEW_RELATED_ID);

            resultModifyApplyment.setChannelApplyNo(String.valueOf(reviewRelatedId));
            resultModifyApplyment.setChannelVar1(applyResp.toJSONString());
            resultModifyApplyment.setState(MchApplyment.STATE_AUDITING);

            String remark = "拉卡拉拓客基本信息变更已发起";
            resultModifyApplyment.setRemark(remark);
            log.debug("拉卡拉拓客基本信息变更发起成功");
        } catch (Exception e) {
            resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]");
            resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY);
        }

        return new MutablePair<>(resultModifyApplyment, null);
    }

    @Override
    public MutablePair<MchModifyApplyment, MchApplyment> syncChannelModifySettlement(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        MchModifyApplyment resultModifyApplyment = new MchModifyApplyment();

        MchModifyApplyment mchModifyApplyment = mchDataPair.getKey();
        resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId());
        resultModifyApplyment.setState(MchApplyment.STATE_AUDITING);
        MchApplyment mchApplyment = mchDataPair.getValue();

        Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment));

        String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo();
        MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class);

        JSONObject param = new JSONObject();
        param.put(Lklsb2bpayConst.CUSTOMER_NO, mchApplyment.getChannelApplyNo());
        param.put(Lklsb2bpayConst.ACCOUNT_NAME, mchModifyData.getSettAccountName());
        param.put(Lklsb2bpayConst.BANK_NAME, mchModifyData.getSettAccountBankName());
        param.put(Lklsb2bpayConst.BANK_NO, mchModifyData.getBankSubCode());
        param.put(Lklsb2bpayConst.CLEARING_BANK_NO, mchModifyData.getBankCode());
        param.put(Lklsb2bpayConst.ACCOUNT_NO, mchModifyData.getSettAccountNo());
        param.put("accountKind", mchModifyData.getSettAccountType().equals("B")? "57": "58");

        List<Map<String, Object>> attachments = new ArrayList<>();
        param.put("attachments", attachments);
        if (mchModifyData.getSettAccountType().equals("B")) {
            JSONObject imgUploadResult = Lklsb2bpayKit.uploadRequest(isvParams, mchModifyData.getSettAccountLicenseImg(), "OPENING_PERMIT");
            Map<String, Object> attachmentItem = new HashMap<>();
            attachmentItem.put("imgPath", imgUploadResult.getString("url"));
            attachmentItem.put("imgType", "OPENING_PERMIT");
            attachments.add(attachmentItem);
        }

        if (mchModifyData.getSettAccountType().equals("C")) {
            JSONObject imgUploadResult = Lklsb2bpayKit.uploadRequest(isvParams, mchModifyData.getSettAccountLicenseImg(), "BANK_CARD");
            Map<String, Object> attachmentItem = new HashMap<>();
            attachmentItem.put("imgPath", imgUploadResult.getString("url"));
            attachmentItem.put("imgType", "OPENING_PERMIT");
            attachments.add(attachmentItem);
        }

        try {
            JSONObject applyResp = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.SETTLE_CHANGE, isvParams, param);
            Long reviewRelatedId = applyResp.getLong(Lklsb2bpayConst.REVIEW_RELATED_ID);

            resultModifyApplyment.setChannelApplyNo(String.valueOf(reviewRelatedId));
            resultModifyApplyment.setChannelVar1(applyResp.toJSONString());
            resultModifyApplyment.setState(MchApplyment.STATE_AUDITING);

            String remark = "拉卡拉基本信息变更已发起";
            resultModifyApplyment.setRemark(remark);
//            log.debug("云商服3.0基本信息变更发起成功");
            log.debug("拉卡拉拓客基本信息变更发起成功");
        } catch (Exception e) {
            resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]");
            resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY);

            return new MutablePair<>(resultModifyApplyment, null);
        }

        return new MutablePair<>(resultModifyApplyment, null);
    }

    @Override
    public MutablePair<MchModifyApplyment, MchApplyment> syncChannelModifyRate(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        return null;
    }

    @Override
    public MutablePair<MchModifyApplyment, MchApplyment> syncChannelModifySettlementType(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        MchModifyApplymentModel modifyApplymentModel = JSON.parseObject(mchDataPair.left.getApplyDetailInfo(), MchModifyApplymentModel.class);
        String settlementType = modifyApplymentModel.getSettlementType();

        Lklsb2bpayApplymentInfo lklsb2bpayApplymentInfo = JSON.parseObject(mchDataPair.right.getApplyDetailInfo(), Lklsb2bpayApplymentInfo.class);

        JSONObject param = new JSONObject();
        param.put(Lklsb2bpayConst.CUSTOMER_NO, mchDataPair.right.getChannelApplyNo());

        List<JSONObject> fees = new ArrayList<>();
        Map<String, JSONObject> feesMap = new HashMap();
        lklsb2bpayApplymentInfo.getPaywayFeeList().forEach(r -> {

            if (r.getWayCode().startsWith("WX_")) {
                JSONObject fee = new JSONObject();
                fees.add(fee);
                fee.put("feeType", "WECHAT");
                fee.put("fee", r.getFeeRate().multiply(BigDecimal.valueOf(100)));
                feesMap.put(fee.getString("feeType"), fee);
            }

            if (r.getWayCode().startsWith("ALI_")) {
                JSONObject fee = new JSONObject();
                fees.add(fee);
                fee.put("feeType", "ALIPAY");
                fee.put("fee", r.getFeeRate().multiply(BigDecimal.valueOf(100)));
                feesMap.put(fee.getString("feeType"), fee);
            }

            if (r.getWayCode().startsWith("YSF_")) {
                JSONObject fee = new JSONObject();
                fees.add(fee);
                fee.put("feeType", "YSF_DISCOUNT_DEBIT_FEE");
                fee.put("fee", r.getLevelList().get(0).getFeeRate().multiply(BigDecimal.valueOf(100)));
                feesMap.put(fee.getString("feeType"), fee);

                fee = new JSONObject();
                fees.add(fee);
                fee.put("feeType", "DEBIT_CARD");

                // 费率模板限制
                fee.put("fee", "0.5d");
                feesMap.put(fee.getString("feeType"), fee);

                fee = new JSONObject();
                fees.add(fee);
                fee.put("feeType", "YSF_DISCOUNT_CREDIT_FEE");
                fee.put("fee", r.getLevelList().get(0).getFeeRate().multiply(BigDecimal.valueOf(100)));

                feesMap.put(fee.getString("feeType"), fee);

                fee = new JSONObject();
                fees.add(fee);
                fee.put("feeType", "CREDIT_CARD");
                fee.put("fee", r.getLevelList().get(1).getFeeRate().multiply(BigDecimal.valueOf(100)));

                feesMap.put(fee.getString("feeType"), fee);
            }
        });

        param.put("fees", new ArrayList<>(feesMap.values()));
        param.put("settleType", settlementType);
        param.put("productCode", Lklsb2bpayConst.BIZ_CODE_SCAN);

        Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchDataPair.right));
        try {
            JSONObject bizData = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.RATE_CHANGE, isvParams, param);

            String message = bizData.getString("message");
            String reviewRelatedId = bizData.getString("reviewRelatedId");

            if ("SUCCESS".equals(message)) {
                mchDataPair.left.setChannelApplyNo(reviewRelatedId);
                // 通过，次日生效，后续操作见定时任务
                mchDataPair.left.setChannelVar1(processChannelValue(mchDataPair.right.getChannelVar1(), bizData));
                mchDataPair.left.setState(MchApplyment.STATE_AUDITING);

                return new MutablePair<>(mchDataPair.left, null);
            } else {
                // 驳回
                mchDataPair.left.setChannelVar1(processChannelValue(mchDataPair.right.getChannelVar1(), bizData));
                mchDataPair.left.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY);
                mchDataPair.left.setApplyErrorInfo("[" + message + "]");

                return new MutablePair<>(mchDataPair.left, null);
            }
        } catch (Exception e) {
            // 驳回
            mchDataPair.left.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY);
            mchDataPair.left.setApplyErrorInfo("[" + e.getMessage() + "]");

            return new MutablePair<>(mchDataPair.left, null);
        }
    }

    @Override
    public MutablePair<MchModifyApplyment, MchApplyment> queryModifyResult(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        MchModifyApplyment resultModifyApplyment = new MchModifyApplyment();

        MchModifyApplyment modifyApplyment = mchDataPair.getLeft();
        MchApplyment mchApplyment = mchDataPair.getRight();

        Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment));

        JSONObject param = new JSONObject();
        param.put(Lklsb2bpayConst.REVIEW_RELATED_ID, modifyApplyment.getChannelApplyNo());

        JSONObject bizData = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.CHANGE_STATUS_GET, isvParams, param);
        String reviewPass = bizData.getString("reviewPass");
        String reviewResult = bizData.getString("reviewResult");
        if (!ObjectUtils.isEmpty(reviewResult)) {
            resultModifyApplyment.setApplyErrorInfo("[" + reviewResult + "]");
        }

        if ("PASS".equals(reviewPass)) {
            // 通过
            resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData));
            return handleSuccessCase(modifyApplyment, mchDataPair);
        }

        if ("UNPASS".equals(reviewPass)) {
            // 驳回
            resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData));
            resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY);
            resultModifyApplyment.setApplyErrorInfo("[" + bizData.getString("note") + "]");

            return new MutablePair<>(resultModifyApplyment, null);
        }

        return mchDataPair;
    }

    private MutablePair<MchModifyApplyment, MchApplyment> handleSuccessCase(MchModifyApplyment modifyApplyment, MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
        switch (modifyApplyment.getModifyApplyType()) {
            case MchModifyApplyment.MODIFY_TYPE_BASE:
                return localModifyBase(mchDataPair);
            case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT:
                return localModifySettlement(mchDataPair);
            case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT_TYPE:
                return localModifySettlementType(mchDataPair);
            default:
                return mchDataPair;
        }
    }

    private String processChannelValue(String channelVal, JSONObject bizData) {
        JSONObject channelValJSON = StrUtil.isEmptyIfStr(channelVal) ? new JSONObject() : JSON.parseObject(channelVal);
        channelValJSON.putAll(bizData);
        return channelValJSON.toJSONString();
    }
}
