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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jeequan.jeepay.converter.MchInfoConverter;
import com.jeequan.jeepay.core.beans.RequestKitBean;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchModifyApplyment;
import com.jeequan.jeepay.core.exception.ResponseException;
import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentNotifyService;
import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.MchApplyment;
import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity;
import com.jeequan.jeepay.service.impl.MchApplymentService;
import com.jeequan.jeepay.service.impl.MchModifyApplymentService;
import com.jeequan.jeepay.thirdparty.channel.IsvFactory;
import com.jeequan.jeepay.thirdparty.channel.yspay.utils.ApplymentNotify;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.ExecutorService;

@Slf4j
@Service
public class YspayIsvmchApplymentNotifyService implements IIsvmchApplymentNotifyService {

    @Autowired
    private RequestKitBean requestKitBean;

    @Autowired
    private MchApplymentService mchApplymentService;

    @Autowired
    private YspayApplymentApiService yspayApplymentApiService;

    @Autowired
    private YspayMchApplymentService yspayMchApplymentService;

    @Autowired
    private ExecutorService executorService;

    @Autowired
    private MchInfoConverter mchInfoConverter;

    @Autowired
    private MchModifyApplymentService mchModifyApplymentService;

    @Override
    public ResponseEntity<?> retOk(Object params) {
        return ResponseEntity.ok("success");
    }

    /**
     * 银盛入网和签约的回调链接组装参数中，包含了商户号，urlApplyId即商户的applyId
     */
    @Override
    public MutablePair<String, Object> parseParams(HttpServletRequest request, String urlApplyId) {
        try {
            JSONObject reqParamJSON = requestKitBean.getReqParamJSON();
            String bizContent = reqParamJSON.getString("bizContent");
            // 使用TypeReference，防止 ApplymentNotify.Report.thirdMercList的ThirdMerc的类型被擦除
            ApplymentNotify applymentNotify = JSON.parseObject(bizContent, ApplymentNotify.class);

            if (ApplymentNotify.TYPE_MCH_APPLY.equals(applymentNotify.getNotifyType())
                 || ApplymentNotify.TYPE_MCH_SIGN.equals(applymentNotify.getNotifyType())
                 || ApplymentNotify.TYPE_MCH_REPORT.equals(applymentNotify.getNotifyType())
                 || ApplymentNotify.TYPE_MCH_CHANGE.equals(applymentNotify.getNotifyType())) {
                // 这些回调接口参数都由接口参数配置，故将商户号带入其中
                return MutablePair.of(urlApplyId, applymentNotify);
            }

            return null;
        } catch (Exception e) {
            log.error("error", e);
            throw ResponseException.buildText("ERROR");
        }
    }

    @Override
    public MutablePair<com.jeequan.jeepay.core.entity.MchApplyment, ResponseEntity> doNotify(HttpServletRequest request, Object params, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) {

        ApplymentNotify applymentNotify = (ApplymentNotify) params;

        MutablePair<com.jeequan.jeepay.core.entity.MchApplyment, ResponseEntity> result = null;
        switch (applymentNotify.getNotifyType()) {
            case ApplymentNotify.TYPE_MCH_APPLY:
                result = handleAuditApply(applymentNotify, mchApplyment);
                break;
            case ApplymentNotify.TYPE_MCH_CHANGE:
                handleModifyApply(applymentNotify, mchApplyment);
                result = MutablePair.of(null, retOk(null));
                break;
            case ApplymentNotify.TYPE_MCH_SIGN:
                // 签约回调
                result = handleSignApply(applymentNotify, mchApplyment);
                break;
            case ApplymentNotify.TYPE_MCH_REPORT:
                // 报备异步通知
                if ("00".equals(applymentNotify.getStatus())) {
                    // 报备异步处理
                    executorService.execute(() -> yspayMchApplymentService.subMchColl(mchApplyment, applymentNotify.getReport()));
                }

                // 报备回调返回空
                return MutablePair.of(null, retOk(null));
            default:
                result = MutablePair.of(null, retOk(null));
        }

        return result;
    }

    private MutablePair<com.jeequan.jeepay.core.entity.MchApplyment, ResponseEntity> handleSignApply(ApplymentNotify applymentNotify, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) {
        MchApplyment updateRecordAudit = new MchApplyment();

        if ("00".equals(applymentNotify.getStatus())) {
            // 签约成功，完成进件
            updateRecordAudit.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS);
            updateRecordAudit.setApplyErrorInfo("[" + applymentNotify.getAuth().getNote() + "]");
            updateRecordAudit.setApplyId(mchApplyment.getApplyId());
            JSONObject sucJSON = JSON.parseObject(mchApplyment.getSuccResParameter());
            if (sucJSON == null) {
                sucJSON = new JSONObject();
            }
            sucJSON.put("mercId", applymentNotify.getAuth().getMercId());
            updateRecordAudit.setSuccResParameter(sucJSON.toJSONString());
            updateRecordAudit.setChannelMchNo(applymentNotify.getAuth().getMercId());

            // TODO 银盛入网签约完成 业务大厅添加变更数据将T1变为D1并待审核
            if ("yspay".equals(mchApplyment.getIfCode())){
                MchModifyApplymentEntity modifyApplyment=new MchModifyApplymentEntity();
                modifyApplyment.setModifyApplyId(SeqKit.genMchNotifyApplyNo());
                modifyApplyment.setApplyId(mchApplyment.getApplyId());
               // modifyApplyment.setChannelApplyNo(mchApplyment.getChannelApplyNo());
                modifyApplyment.setChannelMchNo(mchApplyment.getChannelMchNo());
                modifyApplyment.setMchNo(mchApplyment.getMchNo());
                modifyApplyment.setIfCode(mchApplyment.getIfCode());
                modifyApplyment.setIfName(mchApplyment.getIfName());
                //商户本次变更前数据
                MchApplyment applyment = mchApplymentService.getById(mchApplyment.getApplyId());
                String jsonString = JSONObject.toJSONString(applyment);
                modifyApplyment.setOriginDetailInfo(jsonString);
                //商户本次变更信息
                modifyApplyment.setApplyDetailInfo("{\"settlementType\":\"D1\"}");
                modifyApplyment.setApplyPageType(applyment.getApplyPageType());
                //变更类型为6 结算类型变更
                modifyApplyment.setModifyApplyType((byte) 6);
                //状态默认为审核中
                modifyApplyment.setState((byte) 1);
                modifyApplyment.setCreatedAt(new Date());
                mchModifyApplymentService.save(modifyApplyment);
            }
            return MutablePair.of(mchInfoConverter.toModel(updateRecordAudit), retOk(null));
        }

        if ("90".equals(applymentNotify.getStatus()) || "99".equals(applymentNotify.getStatus())) {
            // 驳回
            updateRecordAudit.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY);
            updateRecordAudit.setApplyErrorInfo("[" + applymentNotify.getAuth().getNote() + "]");
            updateRecordAudit.setApplyId(mchApplyment.getApplyId());

            return MutablePair.of(mchInfoConverter.toModel(updateRecordAudit), retOk(null));
        }

        return MutablePair.of(null, retOk(null));
    }

    private MutablePair handleAuditApply(ApplymentNotify applymentNotify, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) {
        JSONObject jsonObject = JSON.parseObject(mchApplyment.getApplyDetailInfo());

        String channelVar1 = mchApplyment.getChannelVar1();
        JSONObject channelVarJson;
        try {
            channelVarJson = JSON.parseObject(channelVar1);
        } catch (Exception e) {
            channelVarJson = new JSONObject();
        }

        channelVarJson.putAll(((JSONObject) JSON.toJSON(applymentNotify.getCust())));
        mchApplyment.setChannelVar1(channelVarJson.toJSONString());

        if ("00".equals(applymentNotify.getStatus())) {
            com.jeequan.jeepay.core.entity.MchApplyment signApplyResult = yspayApplymentApiService.signApply(jsonObject, mchApplyment);
            signApplyResult.setChannelVar1(mchApplyment.getChannelVar1());
            return MutablePair.of(signApplyResult, retOk(null));
        }

        if ("90".equals(applymentNotify.getStatus()) || "99".equals(applymentNotify.getStatus())) {
            MchApplyment updateRecordAudit = new MchApplyment();
            // 驳回
            updateRecordAudit.setApplyId(mchApplyment.getApplyId());
            updateRecordAudit.setApplyErrorInfo("[" + applymentNotify.getCust().getNote() + "]");
            updateRecordAudit.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY);
            return MutablePair.of(mchInfoConverter.toModel(updateRecordAudit), retOk(null));
        }

        if ("10".equals(applymentNotify.getStatus())) {
            MchApplyment updateRecordAudit = new MchApplyment();
            updateRecordAudit.setApplyId(mchApplyment.getApplyId());
            updateRecordAudit.setApplyErrorInfo("[" + applymentNotify.getCust().getNote() + "]");
            updateRecordAudit.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_UPSTREAM_MANUAL_REVIEW);
            return MutablePair.of(mchInfoConverter.toModel(updateRecordAudit), retOk(null));
        }

        return MutablePair.of(null, retOk(null));
    }

    private void handleModifyApply(ApplymentNotify applymentNotify, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) {
        ApplymentNotify.Change change = applymentNotify.getChange();
        String changeSysFlowId = change.getChangeSysFlowId();

        MchModifyApplyment modifyApplyment = getModifyApplymentByChannelApplyNo(changeSysFlowId);

        IIsvmchModifyApplymentService isvmchModifyApplymentService = IsvFactory.getIsvMchModifyApplymentService(CS.IF_CODE.YSPAY);

        if (mchApplyment.getState() == MchApplyment.STATE_SUCCESS) {
            // 已经变更完成，直接退出
            return;
        }

        switch (change.getStatus()) {
            case "00": // 变更成功
                handleSuccessfulChange(modifyApplyment, mchApplyment, isvmchModifyApplymentService);
                break;
            case "03": // 待签约
                handleWaitingForSign(modifyApplyment, mchApplyment, isvmchModifyApplymentService);
                break;
            default: // 其他状态统一定为驳回
                handleRejectedState(modifyApplyment, change.getNote());
                break;
        }
    }

    private MchModifyApplyment getModifyApplymentByChannelApplyNo(String channelApplyNo) {
        LambdaQueryWrapper<MchModifyApplymentEntity> qWrapper = Wrappers.lambdaQuery();
        qWrapper.eq(MchModifyApplymentEntity::getChannelApplyNo, channelApplyNo);
        return mchInfoConverter.toModel(mchModifyApplymentService.getOne(qWrapper));
    }

    private void handleSuccessfulChange(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, IIsvmchModifyApplymentService isvmchModifyApplymentService) {
        MutablePair<MchModifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment> mchModifyPair;
        switch (modifyApplyment.getModifyApplyType()) {
            case MchModifyApplyment.MODIFY_TYPE_BASE:
                mchModifyPair = isvmchModifyApplymentService.localModifyBase(new MutablePair<>(modifyApplyment, mchApplyment));
                break;
            case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT:
                mchModifyPair = isvmchModifyApplymentService.localModifySettlement(new MutablePair<>(modifyApplyment, mchApplyment));
                break;
            case MchModifyApplyment.MODIFY_TYPE_RATE:
                mchModifyPair = isvmchModifyApplymentService.localModifyRate(new MutablePair<>(modifyApplyment, mchApplyment));
                break;
            default:
                mchModifyPair = new MutablePair<>(modifyApplyment, mchApplyment);
        }

        updateModificationState(mchModifyPair.getLeft(), mchModifyPair.getRight());
    }

    private void handleWaitingForSign(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, IIsvmchModifyApplymentService isvmchModifyApplymentService) {
        MutablePair<MchModifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment> mchModifyPair = isvmchModifyApplymentService.queryModifyResult(new MutablePair<>(modifyApplyment, mchApplyment));
        updateModificationState(mchModifyPair.getLeft(), mchModifyPair.getRight());
    }

    private void handleRejectedState(MchModifyApplyment modifyApplyment, String note) {
        MchModifyApplymentEntity result = new MchModifyApplymentEntity();
        result.setModifyApplyId(modifyApplyment.getModifyApplyId());
        result.setApplyErrorInfo("[" + note + "]");
        result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY);
        mchModifyApplymentService.updateById(result);
    }

    private void updateModificationState(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) {
        MchModifyApplymentEntity dbEntity = mchInfoConverter.toDbEntity(modifyApplyment);
        MchApplyment dbEntity1 = mchInfoConverter.toDbEntity(mchApplyment);

        // 状态变更就更新
        if (!modifyApplyment.getState().equals(mchApplyment.getState())) {
            mchModifyApplymentService.updateById(dbEntity);

            // 变更成功就更新商户数据
            if (modifyApplyment.getState() == MchApplyment.STATE_SUCCESS) {
                mchApplymentService.updateById(dbEntity1);
            }
        }
    }
}
