package com.buukle.agent.runtime.kernel.service;

import com.buukle.agent.instance.dtvo.vo.SessionVO;
import com.buukle.agent.instance.spi.SessionSpi;
import com.buukle.agent.model.dtvo.complete.LLMEvent;
import com.buukle.agent.model.dtvo.dto.complete.ChatCompletionRequestDTO;
import com.buukle.agent.model.dtvo.dto.complete.ChatMessageDTO;
import com.buukle.agent.model.dtvo.vo.ModelRouteFullVO;
import com.buukle.agent.model.spi.ApiKeySpi;
import com.buukle.agent.runtime.kernel.config.FallbackRouteExecutor;
import com.buukle.agent.runtime.kernel.config.RouteListBuilder;
import com.buukle.agent.runtime.kernel.model.invoke.KernelLlmService;
import com.buukle.agent.runtime.kernel.model.invoke.LlmInteractionMeta;
import com.buukle.agent.runtime.kernel.model.invoke.LlmInteractionType;
import com.buukle.agent.runtime.kernel.port.KernelContext;
import com.buukle.agent.runtime.kernel.port.vo.RuntimeEventDataVO;
import com.buukle.agent.runtime.kernel.port.vo.RuntimeEventVO;
import com.buukle.agent.runtime.kernel.port.vo.SessionStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;

@Slf4j
@Component
@RequiredArgsConstructor
public class TitleService {

    private static final String TITLE_PROMPT =
            "Generate a concise session title (max 25 characters) based on the user's message. " +
                    "Output ONLY the title, no quotes, no extra text.\n\nUser message: ";

    private final SessionSpi sessionSpi;
    private final KernelLlmService kernelLlmService;
    private final ApiKeySpi apiKeySpi;
    private final RouteListBuilder routeListBuilder;
    private final FallbackRouteExecutor fallbackRouteExecutor;
    private final ApplicationEventPublisher eventPublisher;

    @Qualifier("runtimeAsyncExecutor")
    private final Executor asyncExecutor;

    public void generateIfNeeded(KernelContext ctx, String userMessage, Long sessionId) {
        var session = ctx != null ? ctx.getSession() : null;
        if (session == null || !Boolean.TRUE.equals(session.getTitleAutoGenerated())) return;
        if (userMessage == null || userMessage.isBlank()) return;

        asyncExecutor.execute(() -> {
            String title = doGenerateTitle(sessionId, userMessage);
            if (title != null && !title.isBlank()) {
                sessionSpi.updateSession(sessionId, title);
                eventPublisher.publishEvent(new RuntimeEventVO(SessionStatus.TITLE_UPDATED,
                        new RuntimeEventDataVO()
                                .setSessionId(sessionId)
                                .setAssistantReply(title)));
            }
        });
    }

    private String doGenerateTitle(Long sessionId, String userMessage) {
        try {
            SessionVO session = sessionSpi.getSession(sessionId);
            if (session == null || session.getAgentInstanceId() == null) return "";

            List<ModelRouteFullVO> routes = routeListBuilder.fromInstance(session.getAgentInstanceId());

            return fallbackRouteExecutor.execute(routes, (i, route) -> {
                ChatCompletionRequestDTO request = new ChatCompletionRequestDTO()
                        .setModel(route.getModelName())
                        .setStream(true)
                        .setMessages(List.of(
                                new ChatMessageDTO().setRole("user")
                                        .setContent(TITLE_PROMPT + userMessage)));

                String apiKey = resolveApiKey(route);
                StringBuilder content = new StringBuilder();
                CountDownLatch done = new CountDownLatch(1);

                kernelLlmService.stream(
                        route.getCompany(), route.getBaseUrl(), apiKey, route.getModelName(),
                        request,
                        event -> {
                            if (event instanceof LLMEvent.TextDelta(String text)) content.append(text);
                            else if (event instanceof LLMEvent.Finish f) done.countDown();
                        },
                        new LlmInteractionMeta()
                                .setSessionId(sessionId)
                                .setInteractionType(LlmInteractionType.TITLE_GENERATION));

                try {
                    done.await();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                String title = content.toString().trim();
                if (title.isBlank()) throw new RuntimeException("empty");
                return title.length() > 25 ? title.substring(0, 25) : title;
            });
        } catch (Exception e) {
            log.debug("Title generation failed for session {}", sessionId);
            return "";
        }
    }

    private String resolveApiKey(ModelRouteFullVO route) {
        if (route.getApiKeyId() == null) return "";
        try {
            return apiKeySpi.getApiKeyValue(route.getApiKeyId());
        } catch (Exception e) {
            log.warn("Failed to resolve API key id={}", route.getApiKeyId(), e);
            return "";
        }
    }
}
