package cn.axzo.msg.center.im.channel;

import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.msg.center.im.domain.enums.IMSendMessageStatusEnum;
import cn.axzo.msg.center.im.domain.event.IMSendSingleMessageEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 * @description
 *  即时通信渠道工厂
 *
 * @author cold_blade
 * @date 2023/9/27
 * @version 1.0
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class IMChannelHandlerFactory {

    private final List<IMChannelHandler> handlers;

    @EventListener(classes = IMSendSingleMessageEvent.class)
    public void sendSingleMessage(IMSendSingleMessageEvent event) {
        IMChannelHandler handler = handlers.stream()
                .filter(e -> Objects.equals(e.channel(), event.getParam().getChannel()))
                .findFirst()
                .orElse(null);
        if (Objects.isNull(handler)) {
            log.error("[{}] not registered.", event.getParam().getChannel());
            return;
        }
        log.info("start to send single message. event:{}", event);
        retrySendSingleMessage(event, handler);
    }

    @Retryable(value = ServiceException.class, backoff = @Backoff(delay = 1000L, multiplier = 1))
    public void retrySendSingleMessage(IMSendSingleMessageEvent event, IMChannelHandler handler) {
        try {
            if (event.getRetryCounter().longValue() > event.getRetryCnt()) {
                log.warn("failed to retry send single message. event:{}", event);
                event.setStatus(IMSendMessageStatusEnum.FAILED);
            } else {
                handler.sendSingleMessage(event.getParam());
                event.setStatus(IMSendMessageStatusEnum.SUCCESS);
                log.warn("successfully send single message. event:{}", event);
            }
            // 回调函数处理
            event.getParam().getCallback().accept(event);
        } catch (ServiceException e) {
            log.error("broke out some exception while sending single message. event:{}", event);
            event.getRetryCounter().increment();
            throw e;
        }
    }
}
