package com.sonic.common.event;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;

/**
 * 消费消息，用法如下：
 * <pre>
 * // EVENT_TOPIC_KEY = "topic"
 * &#064;Bean
 *     EventConsumer eventConsumer(AppRuntime appRuntime, EventHandlerRepository eventHandlerRepository, ApiStatsClient apiStatsClient) {
 *         Consumer<EventConsumer.EventWrapper> callback = (eventWrapper) -> {
 *             if (eventWrapper.isHandled()) {
 *                 // 只收集被App真正消费的消息.
 *                 String topic = (String)eventWrapper.getExt().get(EVENT_TOPIC_KEY);
 *                 apiStatsClient.reportConsumedEvent(eventWrapper.getEvent(), topic);
 *             }
 *         };
 *         return new DefaultEventConsumer(appRuntime.getAppName(), eventHandlerRepository, callback);
 *     }
 * </pre>
 */
@Slf4j
public class DefaultEventConsumer implements EventConsumer {

    private final EventHandlerRepository handlerRepository;

    private final String appName;
    private final Consumer<EventWrapper> consumeCallback;

    /**
     * 推荐使用 带callback的构造方法 可以通过callback集成apiStatsClient对消息进行治理<br>
     * 见：{@link DefaultEventConsumer#DefaultEventConsumer(java.lang.String, EventHandlerRepository, java.util.function.Consumer)}
     */
    @Deprecated
    public DefaultEventConsumer(String appName, EventHandlerRepository handlerRepository) {
        this(appName, handlerRepository, null);
    }

    public DefaultEventConsumer(String appName, EventHandlerRepository handlerRepository, Consumer<EventWrapper> consumeCallback) {
        this.handlerRepository = handlerRepository;
        this.appName = appName;
        this.consumeCallback = consumeCallback;
    }

    @Override
    public void onEvent(String message) {
        onEvent(message, Collections.emptyMap());

    }

    @Override
    public boolean onEvent(String message, Map<String, Object> ext) {
        Event event;
        // 默认开启日志，如需关闭日志，在调用onEvent的时候，设置logEnable为false
        boolean logEnable = ext == null || Boolean.TRUE.equals(ext.getOrDefault("logEnabled", true));
        if (logEnable) {
            log.info("====MQ CONSUMER===={} , message = {}", appName, message);
        }
        try {
            event = JSONObject.parseObject(message, Event.class);
        } catch (Exception e) {
            log.error("====MQ CONSUMER===={}, parse event error, event = {}", appName, message, e);
            return false;
        }
        boolean handled = handlerRepository.process(event, ext);
        if (consumeCallback != null) {
            consumeCallback.accept(EventWrapper.builder().event(event).consumer(this).isHandled(handled).ext(ext).build());
        }
        return handled;
    }

    @Override
    public EventHandlerRepository registerHandler(Event.EventCode eventCode, EventHandler eventHandler) {
        return handlerRepository.registerHandler(eventCode, eventHandler);
    }

    @Override
    public EventHandlerRepository registerHandlers(List<Event.EventCode> eventCodes, EventHandler eventHandler) {
        return handlerRepository.registerHandlers(eventCodes, eventHandler);
    }
}
