package tech.easyflow.core.runtime;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Component;
import tech.easyflow.common.web.exceptions.BusinessException;

import java.util.Collections;
import java.util.List;

@Component
public class CompositeChatRuntimeManager implements ChatRuntimeManager {

    private static final Logger log = LoggerFactory.getLogger(CompositeChatRuntimeManager.class);

    private final ObjectProvider<ChatRuntimeListener> listenerProvider;

    public CompositeChatRuntimeManager(ObjectProvider<ChatRuntimeListener> listenerProvider) {
        this.listenerProvider = listenerProvider;
    }

    @Override
    public void prepareSession(ChatRuntimeContext context) {
        forEach(listener -> listener.onSessionPrepared(context), "prepareSession", context);
    }

    @Override
    public void recordUserMessage(ChatRuntimeContext context, ChatRuntimeMessage message) {
        forEach(listener -> listener.onUserMessage(context, message), "recordUserMessage", context);
    }

    @Override
    public void recordAssistantDelta(ChatRuntimeContext context, ChatRuntimeMessage message) {
        forEach(listener -> listener.onAssistantDelta(context, message), "recordAssistantDelta", context);
    }

    @Override
    public void recordAssistantCompleted(ChatRuntimeContext context, ChatRuntimeMessage message) {
        forEach(listener -> listener.onAssistantCompleted(context, message), "recordAssistantCompleted", context);
    }

    @Override
    public void recordFailure(ChatRuntimeContext context, Throwable throwable) {
        forEach(listener -> listener.onChatFailed(context, throwable), "recordFailure", context);
    }

    @Override
    public void recordCompleted(ChatRuntimeContext context) {
        forEach(listener -> listener.onChatCompleted(context), "recordCompleted", context);
    }

    @Override
    public List<ChatRuntimeMessage> loadMessages(ChatRuntimeContext context, int limit) {
        for (ChatRuntimeListener listener : listenerProvider.orderedStream().toList()) {
            try {
                List<ChatRuntimeMessage> messages = listener.loadMessages(context, limit);
                if (messages != null && !messages.isEmpty()) {
                    return messages;
                }
            } catch (Exception ex) {
                log.warn("chat runtime loadMessages failed, channel={}, sessionId={}, listener={}",
                        context == null || context.getChannel() == null ? null : context.getChannel().name(),
                        context == null ? null : context.getSessionId(),
                        listener.getClass().getName(),
                        ex);
            }
        }
        return Collections.emptyList();
    }

    private void forEach(ListenerConsumer consumer, String action, ChatRuntimeContext context) {
        for (ChatRuntimeListener listener : listenerProvider.orderedStream().toList()) {
            try {
                consumer.accept(listener);
            } catch (BusinessException ex) {
                throw ex;
            } catch (Exception ex) {
                log.warn("chat runtime {} failed, channel={}, sessionId={}, listener={}",
                        action,
                        context == null || context.getChannel() == null ? null : context.getChannel().name(),
                        context == null ? null : context.getSessionId(),
                        listener.getClass().getName(),
                        ex);
            }
        }
    }

    @FunctionalInterface
    private interface ListenerConsumer {
        void accept(ChatRuntimeListener listener);
    }
}
