package cn.pluss.platform.sxf.audit;

import cn.pluss.platform.IdCardCacheService;
import cn.pluss.platform.IdCardService;
import cn.pluss.platform.SubMerchantApplyOrderService;
import cn.pluss.platform.channel.MerchantAuditService;
import cn.pluss.platform.channel.MerchantCertService;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.exception.BackDataErrorException;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.mapper.MerchantChannelStatusMapper;
import cn.pluss.platform.mapper.NoticeMapper;
import cn.pluss.platform.mapper.UserAppMapper;
import cn.pluss.platform.merchant.AccountService;
import cn.pluss.platform.merchant.MerchantBaseInfoService;
import cn.pluss.platform.merchantChannelImg.MerchantChannelImgService;
import cn.pluss.platform.service.UnknownExceptionService;
import cn.pluss.platform.subMerchant.SubMerchantService;
import cn.pluss.platform.sxf.SxfService;
import cn.pluss.platform.user.impl.GeneralPushUtil;
import cn.pluss.platform.util.*;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author DJH
 */
@Slf4j
@Service("sxfCertService")
@RequiredArgsConstructor
public class SxfCertServiceImpl implements MerchantCertService {

    private final SendMsgUtil sendMsgUtil;
    private final NoticeMapper noticeMapper;
    private final UserAppMapper userAppMapper;

    @Autowired
    private SubMerchantService subMerchantService;

    @Autowired
    private MerchantAuditService sxfMerchantAuditService;

    @Setter(onMethod_ = {@Lazy, @Autowired})
    private MerchantBaseInfoService mbiService;
    @Resource
    private MerchantChannelStatusMapper mcsMapper;

    @Autowired
    private SubMerchantApplyOrderService applyOrderService;
    @Autowired
    private SxfService sxfService;

    @Autowired
    private SubMerchantService smService;

    @Autowired
    @Lazy
    private UnknownExceptionService unknownExceptionService;

    @Autowired
    @Lazy
    private AccountService accountService;

    @Autowired
    @Lazy
    private IdCardService idCardService;

    @Autowired
    @Lazy
    private IdCardCacheService idCardCacheService;

    @Autowired
    private GeneralPushUtil generalPushUtil;

    @Autowired
    @Lazy
    private MerchantChannelImgService channelImgService;

    @Override
    public void wxCert(String merchantId, String merchantCode) {
        JSONObject reqData = new JSONObject();

        reqData.put("backUrl", ParametersUtil.domain + "/api/wxCertCallback/sxf");

        MerchantChannelStatus merchantChannelStatus = new MerchantChannelStatus().setMerchantCode(merchantCode).setChannel(1);
        merchantChannelStatus = mcsMapper.selectOne(new QueryWrapper<>(merchantChannelStatus));

        MerchantBaseInfo mbi = mbiService.getMerchantBaseInfoByMerchantCode(merchantCode);
        Account account = accountService.getRealAccount(mbi.getUserId(), Account.CHANNEL_TYPE_D1);

        if (account.getSettleType().startsWith(Account.SETTLE_TYPE_PRIVATE_ILLEGAL)) {

            // 如果是非法人结算，需要将上送的负责人信息修改为法人
            final IdCard legalIdcard = idCardService.getLegalIdCard(mbi.getUserId());
            reqData.put("contactName", legalIdcard.getCertName());
            reqData.put("contactIdNo", legalIdcard.getCertNo());
            reqData.put("identityType", "00");

            final MerchantChannelImg mciPositive = channelImgService.get(legalIdcard.getImgPositive(), 1);
            final MerchantChannelImg mciNegative = channelImgService.get(legalIdcard.getImgNegative(), 1);

            reqData.put("contactPositivePic", mciPositive.getChannelImgUrl());
            reqData.put("contactOppositePic", mciNegative.getChannelImgUrl());
            reqData.put("contactPersonLicStt", legalIdcard.getCertStartTime().replace("-", ""));
            reqData.put("contactPersonLicEnt", legalIdcard.getCertEndTime().replace("-", ""));

            if (MerchantBaseInfo.MERCH_TYPE_COMPANY.equals(mbi.getMerchantType())) {
                if (StringUtils.isBlank(legalIdcard.getCertAddress())) {
                    IdCardCache idCardCache = new IdCardCache();
                    idCardCache.setCertNo(legalIdcard.getCertNo());
                    final IdCardCache exist = idCardCacheService.getOne(new QueryWrapper<>(idCardCache));
                    if (exist != null) {
                        legalIdcard.setCertAddress(exist.getAddress());
                    }
                }
                reqData.put("legalPersonAddress", legalIdcard.getCertAddress());
            }
        }

        reqData.put("mno", merchantChannelStatus.getMerchantId());


        JSONObject responseData = sxfService.requestApi(SxfConfg.SXF_WX_CERT, reqData);

        String signContent = SignUtils.getSignContent(responseData);
        boolean checkSign;
        try {
            checkSign = RSAUtils.checkSign(SxfConfg.PUBLIC_KEY, signContent, responseData.getString("sign"));
        } catch (Exception e) {
            log.error("商户微信认证申请结果验签失败");
            e.printStackTrace();
            throw new MsgException("商户微信认证结果验签失败");
        }

        if (!checkSign) {
            log.error("商户微信认证结果验签失败");
            throw new MsgException("商户微信认证结果验签失败");
        }

        if (!SxfConfg.SXF_SUCCESS_CODE.equals(responseData.getString("code"))) {
            String msg = responseData.getString("msg");
            log.error("商户微信认证异常: {}", msg);
            // 没有微信子商户号的问题，不做记录
            if (msg.startsWith("商编不存在或无可用微信子商户号") || msg.startsWith("商户已有申请单") || Objects.equals(msg, "未知异常，请稍后重试")) {
                return;
            }

            SubMerchantApplyOrder subMerchantApplyOrder = new SubMerchantApplyOrder();
            subMerchantApplyOrder.setMerchantCode(merchantCode);
            subMerchantApplyOrder.setChannelId(1);
            subMerchantApplyOrder.setStatus("0");
            subMerchantApplyOrder.setResultStatus(SubMerchantApplyOrder.RES_STATUS_COMMIT_ERROR);
            subMerchantApplyOrder.setRemark(msg);
            subMerchantApplyOrder.setSubMchType("WX");
            Date now = new Date();
            subMerchantApplyOrder.setMerchantCode(merchantChannelStatus.getMerchantCode());
            // 先更新
            LambdaUpdateWrapper<SubMerchantApplyOrder> uWrapper = Wrappers.lambdaUpdate();
            uWrapper.eq(SubMerchantApplyOrder::getMerchantCode, merchantCode);
            uWrapper.eq(SubMerchantApplyOrder::getChannelId, 1);
            uWrapper.eq(SubMerchantApplyOrder::getResultStatus, SubMerchantApplyOrder.RES_STATUS_COMMIT_ERROR);
            uWrapper.set(SubMerchantApplyOrder::getStatus, "0")
                    .set(SubMerchantApplyOrder::getResultStatus, SubMerchantApplyOrder.RES_STATUS_COMMIT_ERROR)
                    .set(SubMerchantApplyOrder::getRemark, msg)
                    .set(SubMerchantApplyOrder::getCreateTime, now)
                    .set(SubMerchantApplyOrder::getUpdateTime, now);
            boolean updateFlag = applyOrderService.update(uWrapper);
            if (!updateFlag) {
                applyOrderService.save(subMerchantApplyOrder);
            }

//                throw new MsgException(msg);
        } else {
            JSONObject respData = responseData.getJSONObject("respData");
            if (!SxfConfg.SXF_SUCCESS_CODE.equals(respData.getString("bizCode"))) {
                String msg = respData.getString("bizMsg");
                log.error("商户微信认证请求失败: {}", msg);

                // 没有微信子商户号的问题，不做记录
                if (msg.startsWith("商编不存在或无可用微信子商户号") || msg.startsWith("商户已有申请单") || Objects.equals(msg, "未知异常，请稍后重试")) {
                    return;
                }

                SubMerchantApplyOrder subMerchantApplyOrder = new SubMerchantApplyOrder();
                subMerchantApplyOrder.setMerchantCode(merchantCode);
                subMerchantApplyOrder.setChannelId(1);
                subMerchantApplyOrder.setStatus("0");
                subMerchantApplyOrder.setResultStatus(SubMerchantApplyOrder.RES_STATUS_COMMIT_ERROR);
                subMerchantApplyOrder.setRemark(msg);
                subMerchantApplyOrder.setSubMchType("WX");
                subMerchantApplyOrder.setMerchantCode(merchantChannelStatus.getMerchantCode());
                // 先更新
                LambdaUpdateWrapper<SubMerchantApplyOrder> uWrapper = Wrappers.lambdaUpdate();
                uWrapper.eq(SubMerchantApplyOrder::getMerchantCode, merchantCode);
                uWrapper.eq(SubMerchantApplyOrder::getChannelId, 1);
                uWrapper.eq(SubMerchantApplyOrder::getResultStatus, SubMerchantApplyOrder.RES_STATUS_COMMIT_ERROR);
                uWrapper.set(SubMerchantApplyOrder::getStatus, "0")
                        .set(SubMerchantApplyOrder::getResultStatus, SubMerchantApplyOrder.RES_STATUS_COMMIT_ERROR)
                        .set(SubMerchantApplyOrder::getRemark, msg)
                        .set(SubMerchantApplyOrder::getUpdateTime, new Date());
                boolean updateFlag = applyOrderService.update(uWrapper);
                if (!updateFlag) {
                    applyOrderService.save(subMerchantApplyOrder);
                }
            } else {
                // 将之前微信认证请求发生错误的信息直接全部清理
                // 将之前微信认证请求发生错误的信息直接全部清理
                LambdaQueryWrapper<SubMerchantApplyOrder> qWrapper = Wrappers.lambdaQuery();
                qWrapper.eq(SubMerchantApplyOrder::getMerchantCode, merchantCode)
                        .eq(SubMerchantApplyOrder::getChannelId, 1);

                applyOrderService.remove(qWrapper);

                SubMerchantApplyOrder subMerchantApplyOrder = new SubMerchantApplyOrder();
                subMerchantApplyOrder.setMerchantCode(merchantCode);
                subMerchantApplyOrder.setChannelId(1);
                subMerchantApplyOrder.setApplyNo(respData.getString("wxApplyNo"));
                subMerchantApplyOrder.setStatus("0");
                subMerchantApplyOrder.setSubMchType("WX");
                subMerchantApplyOrder.setMerchantCode(merchantChannelStatus.getMerchantCode());
                applyOrderService.save(subMerchantApplyOrder);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void wxReCert(String merchantId, String merchantCode) {
        SubMerchantApplyOrder subMerchantApplyOrder = new SubMerchantApplyOrder()
                .setMerchantCode(merchantCode).setStatus("1");
        subMerchantApplyOrder = applyOrderService.getOne(new QueryWrapper<>(subMerchantApplyOrder));

        try {
            wxCertCancel(merchantId, subMerchantApplyOrder);
        } catch (Exception e) {
            log.error("微信认证取消异常 {}", e.getMessage());
        }
        // 取消微信认证不影响再次认证的操作
        wxCert(merchantId, merchantCode);
    }

    @Override
    public JSONObject wxCertResult(String merchantId, String wxApplyNo) {
        JSONObject reqData = new JSONObject();
        reqData.put("mno", merchantId);
        reqData.put("wxApplyNo", wxApplyNo);

        JSONObject result = sxfService.requestApi(SxfConfg.SXF_WX_CERT_RESULT, reqData);

        String signContent = SignUtils.getSignContent(result);
        try {
            boolean sign = RSAUtils.checkSign(SxfConfg.PUBLIC_KEY, signContent, result.getString("sign"));

            // 验签不通过，下一个
            if (!sign) {
                unknownExceptionService.save(new BackDataErrorException("随行付-获取商户微信实名进度结果-验签异常"));
                return result;
            }
        } catch (Exception e) {
            unknownExceptionService.save(new BackDataErrorException("随行付-获取商户微信实名进度结果-验签异常"));
        }

        String code = result.getString("code");

        if (SxfConfg.SXF_NO_PERMIT.equals(code)) {
            log.warn("随行付-进件相关功能未开通");
            return result;
        }

        if (!SxfConfg.SXF_SUCCESS_CODE.equals(code)) {
            BackDataErrorException dataErrorException = new BackDataErrorException("商户微信实名认证申请结果查询失败");
            unknownExceptionService.save(dataErrorException);

            return result;
        }

        JSONObject respData = result.getJSONObject("respData");
        if (!respData.getString("bizCode").equals(SxfConfg.SXF_SUCCESS_CODE)) {
            log.info("商户号：" + merchantId + respData.getString("bizMsg"));
            return result;
        }

        // 执行微信商户认证申请结果回调
        try {
            if (respData.getString("wxApplyNo") == null) {
                respData.put("wxApplyNo", wxApplyNo);
            }
            wxCertCallback(respData);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询随行付商户微信认证状态回调报错，报错的商户商户号为 : " + merchantId);
        }

        return result;
    }

    @Override
    public JSONObject wxCertCallback(JSONObject certResult) {
        log.info("微信认证审核回调数据：\n {}", certResult.toJSONString());

        String idenStatus = certResult.getString("idenStatus");
        if ("applyment_state_canceled".equalsIgnoreCase(idenStatus)) {
            log.info(certResult.getString("bizMsg"));
            if (certResult.getString("wxApplyNo") != null) {
                LambdaQueryWrapper<SubMerchantApplyOrder> qWrapper = Wrappers.lambdaQuery();
                qWrapper.eq(SubMerchantApplyOrder::getApplyNo, certResult.getString("wxApplyNo"))
                        .eq(SubMerchantApplyOrder::getChannelId, 1);
                SubMerchantApplyOrder one = applyOrderService.getOne(qWrapper);
                one.setStatus("1");
                one.setResultStatus("APPLYMENT_STATE_CANCELED");
                one.setRemark("商户此申请单已作废");
                applyOrderService.updateById(one);
            }

            return SxfConfg.ok();
        }

        if (certResult.getString("wxApplyNo") == null) {
            return SxfConfg.ok();
        }

        SubMerchantApplyOrder subMerchantApplyOrder = new SubMerchantApplyOrder().setApplyNo(certResult.getString("wxApplyNo")).setSubMchType("WX");
        SubMerchantApplyOrder existData = applyOrderService.getOne(new QueryWrapper<>(subMerchantApplyOrder));

        if (existData == null) {
            log.error("无法获取对应工单信息");
            return SxfConfg.ok();
        }

        UserApp userApp = userAppMapper.selectByMerchantCode(existData.getMerchantCode());

        // 默认处理过
        if ("1".equals(existData.getStatus())) {
            log.info("该工单已处理过");
            return SxfConfg.ok();
        }

        existData.setStatus("1");

        existData.setResultStatus(idenStatus);

        if ("APPLYMENT_STATE_WAITTING_FOR_AUDIT".equals(idenStatus)) {
            // 工单未处理, 请耐心等待1~2个工作日，微信支付将会完成审核
            existData.setStatus("0");
            log.info("认证申请审核中");
        }

        if ("APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT".equals(idenStatus)) {
            log.error("待确认联系信息");
        }

        if ("APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON".equals(idenStatus)) {
            log.info("待商户验证");
        }

        if ("APPLYMENT_STATE_PASSED".equals(idenStatus)) {
            log.info("审核通过");
        }

        if ("APPLYMENT_STATE_REJECTED".equals(idenStatus)) {
            log.error("审核驳回");
        }

        if ("APPLYMENT_STATE_FREEZED".equals(idenStatus)) {
            log.error("审核驳回");
        }

        if ("APPLYMENT_STATE_CANCELED".equals(idenStatus)) {
            log.error("审核驳回");
        }

        if ("APPLYMENT_STATE_OPENACCOUNT".equals(idenStatus)) {
            log.info("已做过实名认证");
            return SxfConfg.ok();
        }

        if ("APPLYMENT_STATE_WAITTING_FOR_AUDIT".equals(idenStatus)) {
            log.info("等待审核");
            existData.setRemark("等待微信审核");
        }

        List<String> alisaList = new ArrayList<>();
        alisaList.add(userApp.getUserId() + "");
        if (StringUtils.isNotEmpty(certResult.getString("infoQrcode"))) {
            existData.setInfoQrcode(certResult.getString("infoQrcode"));
            existData.setRemark("");

            String content = "请商户进行微信实名认证，短信将发送至商户联系人手机号，已认证可忽略";
            generalPushUtil.sendAllPlatByAlias(alisaList, "商户微信认证通知", content, "1");

            Notice notice = new Notice(1, 1, userApp);
            notice.setConrtent(content);
            noticeMapper.saveNotice(notice);

            QueryWrapper<MerchantBaseInfo> queryWrapper = new QueryWrapper<MerchantBaseInfo>().eq("userId", userApp.getUserId());
            MerchantBaseInfo merchantBaseInfo = mbiService.getOne(queryWrapper);

            try {
                sendMsgUtil.verifyMsg(merchantBaseInfo.getContactMobile(), userApp.getMerchantCode() + "?i=1");
            } catch (MsgException e) {
                log.error(e.getMessage());
            }
        }

        if (StringUtils.isNotEmpty(certResult.getString("rejectCode"))) {
            existData.setResultStatus(certResult.getString("rejectCode"));
        }

        if (StringUtils.isEmpty(certResult.getString("infoQrcode")) && StringUtils.isNotEmpty(certResult.getString("rejectInfo"))) {
            Notice notice = new Notice(1, 1, userApp);
            String pushMsg = "您好！您的商户微信认证因“##”被驳回，请联系收银呗客服修改资料并重新审核";
            pushMsg = pushMsg.replace("##", certResult.getString("rejectInfo"));
            notice.setConrtent(pushMsg);
            noticeMapper.saveNotice(notice);

            generalPushUtil.sendAllPlatByAlias(alisaList, "商户微信认证通知", pushMsg, "1");
            existData.setRemark(certResult.getString("rejectInfo"));
        }

        existData.setUpdateTime(new Date());
        applyOrderService.updateById(existData);

        return SxfConfg.ok();
    }

    @Override
    public void wxCertCancel(String merchantId, SubMerchantApplyOrder subMerchantApplyOrder) {
        JSONObject reqData = new JSONObject();
        reqData.put("mno", merchantId);
        reqData.put("wxApplyNo", subMerchantApplyOrder.getApplyNo());

        JSONObject response = sxfService.requestApi(SxfConfg.SXF_WX_CERT_CANCEL, reqData);

        boolean sign;
        try {
            sign = sxfService.checkSign(response);
        } catch (Exception e) {
            log.error("商户微信认证申请验签失败, {}", e.getMessage());
            throw new MsgException("商户微信认证申请验签失败");
        }

        if (!sign) {
            throw new MsgException("商户微信认证申请验签失败");
        }

        if (!SxfConfg.SXF_SUCCESS_CODE.equals(response.getString("code"))) {
            throw new MsgException(response.getString("msg"));
        }

        JSONObject respData = response.getJSONObject("respData");

        if (!SxfConfg.SXF_SUCCESS_CODE.equals(respData.get("bizCode"))) {
            throw new MsgException(respData.getString("bizMsg"));
        }

        // 取消进件信息后需要修改状态
        subMerchantApplyOrder.setStatus("2").setUpdateTime(new Date());
        applyOrderService.updateById(subMerchantApplyOrder);
    }

    @Override
    public void wxCertAuthStatus(String merchantId) {
        SubMerchant condition = new SubMerchant();
        condition.setMerchantId(merchantId);
        condition.setChannelTypeId("1");
        condition.setSubMchType("wx");

        SubMerchant sm = smService.getOne(new QueryWrapper<>(condition).last("LIMIT 1"));
        if (sm == null) {
            log.warn("【{}】没有查询到微信子商户信息, 开始查询微信子商户号", merchantId);

            JSONObject param = new JSONObject();
            param.put("merchantId", merchantId);

            try {
                sxfMerchantAuditService.merchantAuditResult(param);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        sm = smService.getOne(new QueryWrapper<>(condition).last("LIMIT 1"));
        if (sm == null) {
            return;
        }

        JSONObject param = new JSONObject();
        param.put("subMchId", sm.getSubMchId());

        JSONObject jsonObject = sxfService.requestApi(SxfConfg.SXF_WX_CERT_STATUS, param);

        String signContent = SignUtils.getSignContent(jsonObject);
        try {
            RSAUtils.checkSign(SxfConfg.PUBLIC_KEY, signContent, jsonObject.getString("sign"));
        } catch (Exception e) {
            throw new BackDataErrorException("随行付-获取商户微信实名进度结果-验签异常");
        }

        String code = jsonObject.getString("code");
        JSONObject respData = jsonObject.getJSONObject("respData");
        if (!Objects.equals(SxfConfg.SXF_SUCCESS_CODE, code)) {
            log.warn("【{}】" + jsonObject.getString("msg"), merchantId);
            return;
        }

        String bizMsg = respData.getString("bizMsg");
        String bizCode = respData.getString("bizCode");
        if (!Objects.equals(SxfConfg.SXF_SUCCESS_CODE, bizCode)) {
            log.warn("【{}】" + bizMsg, merchantId);
            return;
        }

        String authStatus = respData.getString("authStatus");
        if (Objects.equals(authStatus, "AUTHORIZE_STATE_AUTHORIZED")) {
            LambdaUpdateWrapper<MerchantChannelStatus> uWrapper = Wrappers.lambdaUpdate();
            uWrapper.eq(MerchantChannelStatus::getChannel, 1)
                    .eq(MerchantChannelStatus::getMerchantId, merchantId)
                    .set(MerchantChannelStatus::getAuthorizationStatus, MerchantChannelStatus.AUTHORIZATION_STATUS_AUTHORIZED)
                    .set(MerchantChannelStatus::getUpdateTime, new Date());
            mcsMapper.update(null, uWrapper);
        }
    }
}
