package cn.axzo.msg.center.inside.notices.listener;

import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.msg.center.api.enums.MsgStateEnum;
import cn.axzo.msg.center.dal.MessageRecordDao;
import cn.axzo.msg.center.domain.dto.MsgBody4GuestDTO;
import cn.axzo.msg.center.domain.entity.MessageRecord;
import cn.axzo.msg.center.inside.notices.event.SendMessageEvent;
import cn.axzo.msg.center.inside.notices.service.NewImService;
import cn.azxo.framework.common.utils.LogUtil;
import cn.azxo.framework.common.utils.LogUtil.ErrorLevel;
import cn.azxo.framework.common.utils.LogUtil.ErrorType;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.event.EventListener;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @ClassName SendMessageListener
 * @Description
 * @Author zhangran
 * @Date 2022/4/8 11:44
 **/
@Component
@Slf4j
public class SendMessageListener {

    @Resource
    private NewImService imService;
    @Resource
    private MessageRecordDao messageRecordDao;
    @Resource
    private SendMessageListener sendMessageListener;

    @EventListener(classes = SendMessageEvent.class)
    public void sendMessage(SendMessageEvent event) {
        log.info("sendMessage event:{}", JSONUtil.toJsonStr(event));
        sendMessageListener.send(event);

        MessageRecord messageRecord = new MessageRecord();
        messageRecord.setId(event.getMsgId());
        messageRecord.setRetryCount(event.getRetryCounting().get());
        messageRecord.setFailCause(event.getErrMsg());
        if (event.getIsSend().get()) {
            messageRecord.setState(MsgStateEnum.HAS_BEEN_SENT);
            messageRecord.setEventSource("");
        } else {
            messageRecord.setState(MsgStateEnum.UNSENT);
            messageRecord.setEventSource(JSON.toJSONString(event.getMessage()));
        }
        messageRecordDao.updateById(messageRecord);
    }


    /**
     * 发送消息推送，默认重试三次
     *
     * @param event
     */
    @Retryable(value = ServiceException.class, backoff = @Backoff(delay = 1000L, multiplier = 1))
    public void send(SendMessageEvent event) {
        try {
            MsgBody4GuestDTO dto = new MsgBody4GuestDTO();
            BeanUtils.copyProperties(event.getMessage(), dto);
            log.info("SendMessageListener#send event value={}", JSONUtil.toJsonStr(event));
            imService.syncSendImMessage(dto);
        } catch (ServiceException e) {
            event.getRetryCounting().getAndIncrement();
            throw e;
        }

    }

    /**
     * 重试失败，默认恢复方法 用户打印日志和记录最后一次错误信息
     *
     * @param e
     * @param event
     * @return
     */
    @Recover
    public void recover(ServiceException e, SendMessageEvent event) {
        event.setErrMsg(e.getMessage());
        event.getIsSend().compareAndSet(true, false);
        LogUtil.error(ErrorLevel.P1, ErrorType.ERROR_INNER_SERVICE, "发送消息失败", event.getMsgId(),
                e.getMessage());
    }

}
