package com.pablotj.ai.chat.application.usecase;

import com.pablotj.ai.chat.application.dto.ConversationMessageDto;
import com.pablotj.ai.chat.application.mapper.ConversationMapper;
import com.pablotj.ai.chat.domain.exception.AiServiceUnavailableException;
import com.pablotj.ai.chat.domain.exception.ConversationNotFoundException;
import com.pablotj.ai.chat.domain.model.Conversation;
import com.pablotj.ai.chat.domain.model.ConversationId;
import com.pablotj.ai.chat.domain.model.ConversationMessage;
import com.pablotj.ai.chat.domain.model.ConversationSummary;
import com.pablotj.ai.chat.domain.model.MessageContent;
import com.pablotj.ai.chat.domain.repository.ConversationRepository;
import com.pablotj.ai.chat.domain.service.AiConversationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Use case for processing user messages and generating AI responses.
 * Orchestrates the complete conversation flow including AI response generation.
 */
@Service
@Transactional
public class ProcessUserMessageUseCase {

    private static final Logger logger = LoggerFactory.getLogger(ProcessUserMessageUseCase.class);

    private final ConversationRepository conversationRepository;
    private final AiConversationService aiConversationService;
    private final ConversationMapper conversationMapper;

    public ProcessUserMessageUseCase(
            ConversationRepository conversationRepository,
            AiConversationService aiConversationService,
            ConversationMapper conversationMapper) {
        this.conversationRepository = conversationRepository;
        this.aiConversationService = aiConversationService;
        this.conversationMapper = conversationMapper;
    }

    /**
     * Processes a user message and generates an AI response.
     *
     * @param conversationIdValue the conversation ID as string
     * @param userMessageText     the user's message text
     * @return the AI response message DTO
     * @throws ConversationNotFoundException if the conversation doesn't exist
     * @throws AiServiceUnavailableException if the AI service is unavailable
     */
    public ConversationMessageDto execute(String conversationIdValue, String userMessageText) {
        ConversationId conversationId = ConversationId.of(conversationIdValue);
        MessageContent userMessageContent = MessageContent.of(userMessageText);

        logger.debug("Processing user message for conversation: {}", conversationId);

        // Retrieve conversation
        Conversation conversation = conversationRepository
                .findById(conversationId)
                .orElseThrow(() -> new ConversationNotFoundException(conversationId));

        // Create user message
        ConversationMessage userMessage = ConversationMessage.createUserMessage(
                conversation.getConversationId(), userMessageContent);

        // Add user message to conversation
        conversation = conversation.addMessage(userMessage);

        // Update conversation summary if it's the first message
        if (conversation.getMessageCount() == 1) {
            ConversationSummary newSummary = ConversationSummary.fromFirstMessage(userMessageContent);
            conversation = conversation.updateSummary(newSummary);
        }

        // Generate AI response
        MessageContent aiResponseContent = aiConversationService.generateResponse(
                conversation.getMessages(), userMessage);

        ConversationMessage aiMessage = ConversationMessage.createAssistantMessage(
                conversation.getConversationId(), aiResponseContent);

        // Add AI message to conversation
        conversation = conversation.addMessage(aiMessage);

        // Save updated conversation
        conversationRepository.save(conversation);

        logger.info("Successfully processed message and generated AI response for conversation: {}",
                conversation.getConversationId());

        return conversationMapper.toMessageDto(aiMessage);
    }
}
