package com.jeequan.jeepay.pay.mq;

import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.components.mq.model.MchAuditThirdNotifyMQ;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.converter.MchInfoConverter;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.openapi.AccessError;
import com.jeequan.jeepay.core.model.openapi.AccessReq;
import com.jeequan.jeepay.core.model.openapi.AccessResp;
import com.jeequan.jeepay.core.model.openapi.biz.AuditResultResp;
import com.jeequan.jeepay.db.entity.MchAppEntity;
import com.jeequan.jeepay.db.entity.MchApplyment;
import com.jeequan.jeepay.db.entity.MchNotifyRecord;
import com.jeequan.jeepay.db.entity.MchStore;
import com.jeequan.jeepay.pay.util.ApiResKit;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchApplymentService;
import com.jeequan.jeepay.service.impl.MchNotifyRecordService;
import com.jeequan.jeepay.service.impl.MchStoreService;
import com.jeequan.jeepay.thirdparty.channel.yspay.YspayApplymentApiService;
import com.jeequan.jeepay.thirdparty.channel.yspay.YspayMchApplymentService;
import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService;
import lombok.AllArgsConstructor;
import lombok.Cleanup;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
@Component
public class MchAuditThirdNotifyMQReceiver implements MchAuditThirdNotifyMQ.IMQReceiver {

    @Autowired
    private MchApplymentService mchApplymentService;

    @Autowired
    private YspayApplymentApiService yspayApplymentApiService;

    @Autowired
    private YspayMchApplymentService yspayMchApplymentService;

    @Autowired
    private ConfigContextQueryService configContextQueryService;

    @Autowired
    private IMQSender mqSender;

    @Autowired
    private MchInfoConverter infoConverter;

    @Autowired
    private MchNotifyRecordService mchNotifyRecordService;

    @Autowired
    private MchAppService mchAppService;

    @Autowired
    private MchInfoConverter mchInfoConverter;
    @Autowired
    private MchStoreService mchStoreService;

    @Override
    public void receive(MchAuditThirdNotifyMQ.MsgPayload payload) {

        try {
            log.info("接收商户通知MQ, msg={}", payload.toString());

            MchApplyment mchApplyment = mchApplymentService.getById(payload.getApplyId());

            // 通知地址为空
            if (ObjUtil.isEmpty(mchApplyment.getNotifyUrl())) {
                return;
            }

            String orderId = mchApplyment.getApplyId() + "_" + mchApplyment.getUpdatedAt().getTime();
            MchNotifyRecord auditOrder = mchNotifyRecordService.findAuditOrder(orderId);
            MchStore mchStore = mchStoreService.getByMchApplyId(mchApplyment.getApplyId());

            if (auditOrder != null) {
                return;
            }

            AccessResp body = bulidNotifyData(mchApplyment, mchStore);

            auditOrder = new MchNotifyRecord();
            auditOrder.setOrderId(orderId);
            auditOrder.setOrderType(MchNotifyRecord.TYPE_AUDIT);
            auditOrder.setMchNo(mchApplyment.getMchNo());
            auditOrder.setIsvNo(mchApplyment.getIsvNo());
            auditOrder.setNotifyBody(JSON.toJSONString(body));
            auditOrder.setAppId(mchApplyment.getAutoConfigMchAppId());
            auditOrder.setNotifyUrl(mchApplyment.getNotifyUrl());
            auditOrder.setNotifyPostType(CS.NOTIFY_POST_TYPE.POST_JSON);
            auditOrder.setResResult("");
            auditOrder.setNotifyCount(0);
            auditOrder.setMchOrderNo(mchApplyment.getSubApplyId());
            auditOrder.setState(MchNotifyRecord.STATE_ING);

            try {
                mchNotifyRecordService.save(auditOrder);
            } catch (Exception e) {
                log.info("回调通知数据插入失败", e);
                log.info("数据库已存在[{}]消息，本次不再推送。", auditOrder.getOrderId());
                return;
            }

            MchNotifyRecord record = mchNotifyRecordService.findAuditOrder(orderId);
            if(record == null || record.getState() != MchNotifyRecord.STATE_ING){
                log.info("查询通知记录不存在或状态不是通知中");
                return;
            }
            if( record.getNotifyCount() >= record.getNotifyCountLimit() ){
                log.info("已达到最大发送次数");
                return;
            }

            Long notifyId = record.getNotifyId();

            //1. (发送结果最多6次)
            int currentCount = record.getNotifyCount() + 1;

            String notifyUrl = record.getNotifyUrl();
            String res = "";
            try {
                int timeout = 20000;
                // body形式
                @Cleanup HttpResponse httpResponse =  HttpUtil.createPost(record.getNotifyUrl())
                        .body(record.getNotifyBody(), ContentType.JSON.getValue())
                        .timeout(timeout)
                        .execute();
                res = httpResponse.body();
            } catch (Exception e) {
                log.error("http error", e);
                res = "连接["+ UrlBuilder.of(notifyUrl).getHost() +"]异常:【" + e.getMessage() + "】";
            }

            //通知成功
            if("SUCCESS".equalsIgnoreCase(res)){
                mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_SUCCESS, res);
                return;
            }

            //通知次数 >= 最大通知次数时， 更新响应结果为异常， 不在继续延迟发送消息
            if( currentCount >= record.getNotifyCountLimit() ){
                mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_FAIL, res);
                return;
            }

            // 继续发送MQ 延迟发送
            mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_ING, res);
            // 通知延时次数
            //        1   2  3  4   5   6
            //        0  30 60 90 120 150
            mqSender.send(MchAuditThirdNotifyMQ.build(payload.getApplyId(), MchAuditThirdNotifyMQ.TYPE_AUDIT), currentCount * 30);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 通知参数
     *
     * @param payOrder
     * @param mchStore
     * @return
     */
    private AccessResp bulidNotifyData(MchApplyment payOrder, MchStore mchStore) {
        AccessReq req = new AccessReq();
        req.setAppId(payOrder.getAutoConfigMchAppId());
        MchAppEntity mchApp = mchAppService.getById(payOrder.getAutoConfigMchAppId());
        req.setAppInfo(mchInfoConverter.toModel(mchApp));
        req.setPlatPriKey(ApiResKit.getKey());

        AuditResultResp bizResp = new AuditResultResp(mchInfoConverter.toModel(payOrder));
        bizResp.setMchStore(mchStore);
        // 生成通知
        return new AccessResp(AccessError.SUCCESS, bizResp, req);
    }
}
