package com.emonster.taroaichat.service.llm.openrouter;

import com.emonster.taroaichat.config.ApplicationProperties;
import com.emonster.taroaichat.service.llm.TarotPrompts;
import com.emonster.taroaichat.service.llm.dto.AIResponse;
import com.emonster.taroaichat.service.llm.dto.TarotCardData;
import com.emonster.taroaichat.service.llm.openrouter.tools.AIToolManager;
import com.emonster.taroaichat.service.llm.openrouter.tools.AITool;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Unified AI service for both chat conversations and tarot reading interpretations.
 * Uses OpenRouter with direct HTTP calls for simple, reliable AI interactions.
 */
@Service
public class AIService {

    private static final Logger LOG = LoggerFactory.getLogger(AIService.class);

    private final OpenRouterClient openRouterClient;
    private final ApplicationProperties applicationProperties;
    private final TarotPrompts tarotPrompts;
    private final AIToolManager toolManager;
    private final ObjectMapper objectMapper;

    public AIService(OpenRouterClient openRouterClient,
                     ApplicationProperties applicationProperties,
                     TarotPrompts tarotPrompts,
                     AIToolManager toolManager,
                     ObjectMapper objectMapper) {
        this.openRouterClient = openRouterClient;
        this.applicationProperties = applicationProperties;
        this.tarotPrompts = tarotPrompts;
        this.toolManager = toolManager;
        this.objectMapper = objectMapper;
    }

    /**
     * Generate a concise summary of a tarot reading interpretation.
     * This summary is used as context for future chat messages instead of the full interpretation.
     *
     * @param selectedCards List of selected cards with positions
     * @param fullInterpretation The full tarot reading interpretation
     * @return Concise summary suitable for chat context
     */
    public String generateReadingSummary(List<TarotCardData> selectedCards, String fullInterpretation) {
        try {
            String systemPrompt = tarotPrompts.getSummarySystemPrompt();
            String userPrompt = tarotPrompts.buildSummaryPrompt(selectedCards, fullInterpretation);

            List<OpenRouterClient.ChatCompletionRequest.Message> messages = Arrays.asList(
                new OpenRouterClient.ChatCompletionRequest.Message("system", systemPrompt),
                new OpenRouterClient.ChatCompletionRequest.Message("user", userPrompt)
            );

            return callAI(messages, false);
        } catch (Exception e) {
            LOG.error("Error generating reading summary", e);
            // Fallback to a basic summary
            return buildBasicSummary(selectedCards);
        }
    }

    /**
     * Generate AI response for general chat conversation as a stream with context bridging.
     * This method includes tool results from Phase 1 to guide the streaming response in Phase 2.
     *
     * @param userMessage The user's message
     * @param conversationHistory Previous messages in the conversation
     * @param hasCardsSelected Whether the session has cards selected (for conversational reading flow)
     * @param enableTools Whether to enable tool calling in this response
     * @param cardData The actual card data if available
     * @param sessionStatus The current session status for state-specific prompts
     * @param toolResults Tool results from Phase 1 to guide the response
     * @return A Flux stream of AI response chunks.
     */
    public Flux<String> generateChatResponseStreamWithContext(String userMessage, List<String> conversationHistory, boolean hasCardsSelected, boolean enableTools, List<TarotCardData> cardData, String sessionStatus, List<AITool.ToolResult> toolResults) {
        try {
            List<OpenRouterClient.ChatCompletionRequest.Message> messages = buildChatMessagesWithContext(userMessage, conversationHistory, hasCardsSelected, sessionStatus, cardData, toolResults);

            ApplicationProperties.OpenRouter openRouter = applicationProperties.getOpenrouter();
            String model = openRouter.getModel().getPrimary();

            OpenRouterClient.ChatCompletionRequest request = new OpenRouterClient.ChatCompletionRequest();
            request.model = model;
            request.messages = messages;
            request.temperature = openRouter.getParameters().getTemperature();
            request.maxTokens = openRouter.getParameters().getMaxTokens();
            request.topP = openRouter.getParameters().getTopP();

            // Don't add tools in Phase 2 - tools were already called in Phase 1
            LOG.debug("Calling AI stream with model: {} (Phase 2: context bridging, tools disabled, state: {})", model, sessionStatus);

            return openRouterClient.streamChatCompletion(request);

        } catch (Exception e) {
            LOG.error("Error generating chat response stream with context", e);
            return Flux.error(e);
        }
    }

    /**
     * Generate AI response for general chat conversation as a stream with card data and session status.
     * This ensures the AI has context about the session state and actual cards.
     *
     * @param userMessage The user's message
     * @param conversationHistory Previous messages in the conversation
     * @param hasCardsSelected Whether the session has cards selected (for conversational reading flow)
     * @param enableTools Whether to enable tool calling in this response
     * @param cardData The actual card data if available
     * @param sessionStatus The current session status for state-specific prompts
     * @return A Flux stream of AI response chunks.
     */
    public Flux<String> generateChatResponseStreamWithCards(String userMessage, List<String> conversationHistory, boolean hasCardsSelected, boolean enableTools, List<TarotCardData> cardData, String sessionStatus) {
        try {
            List<OpenRouterClient.ChatCompletionRequest.Message> messages = buildChatMessages(userMessage, conversationHistory, hasCardsSelected, sessionStatus);

            // Add card data to context if available
            if (cardData != null && !cardData.isEmpty()) {
                StringBuilder cardInfo = new StringBuilder("Selected cards for this reading:\n");
                for (TarotCardData card : cardData) {
                    cardInfo.append("- ").append(card.getPosition()).append(": ")
                           .append(card.getName())
                           .append(card.isReversed() ? " (Reversed)" : "")
                           .append("\n");
                }
                messages.add(new OpenRouterClient.ChatCompletionRequest.Message("system", cardInfo.toString()));
            }

            ApplicationProperties.OpenRouter openRouter = applicationProperties.getOpenrouter();
            String model = openRouter.getModel().getPrimary();

            OpenRouterClient.ChatCompletionRequest request = new OpenRouterClient.ChatCompletionRequest();
            request.model = model;
            request.messages = messages;
            request.temperature = openRouter.getParameters().getTemperature();
            request.maxTokens = openRouter.getParameters().getMaxTokens();
            request.topP = openRouter.getParameters().getTopP();

            // Add tools if available and enabled - let AI decide whether to use them
            if (enableTools && toolManager.hasTools()) {
                request.tools = new ArrayList<>(toolManager.getToolsForApiCall());
                request.toolChoice = "auto"; // Let AI decide when to use tools
                LOG.debug("Added {} tools to streaming AI request", toolManager.getToolCount());
            }

            LOG.debug("Calling AI stream with model: {} (tools enabled: {}, cards: {}, state: {})", model, enableTools && toolManager.hasTools(), cardData != null ? cardData.size() : 0, sessionStatus);

            return openRouterClient.streamChatCompletion(request);

        } catch (Exception e) {
            LOG.error("Error generating chat response stream with cards", e);
            return Flux.error(e);
        }
    }

    /**
     * Generate a post-card selection greeting with streaming support.
     * This allows the greeting to appear progressively for better UX.
     *
     * @param selectedCards The cards that were selected
     * @return A Flux stream of greeting message chunks
     */
    public Flux<String> generatePostCardSelectionGreetingStream(List<TarotCardData> selectedCards) {
        try {
            // Generate greeting without card details to prevent interpretation bias
            String greetingPrompt = tarotPrompts.getPostCardSelectionGreeting(selectedCards);

            // Use the specific system prompt for post-card selection
            String systemPrompt = tarotPrompts.getPostCardSelectionSystemPrompt();

            List<OpenRouterClient.ChatCompletionRequest.Message> messages = Arrays.asList(
                new OpenRouterClient.ChatCompletionRequest.Message("system", systemPrompt),
                new OpenRouterClient.ChatCompletionRequest.Message("user", greetingPrompt)
            );

            ApplicationProperties.OpenRouter openRouter = applicationProperties.getOpenrouter();
            String model = openRouter.getModel().getPrimary();

            OpenRouterClient.ChatCompletionRequest request = new OpenRouterClient.ChatCompletionRequest();
            request.model = model;
            request.messages = messages;
            request.temperature = openRouter.getParameters().getTemperature();
            request.maxTokens = openRouter.getParameters().getMaxTokens();
            request.topP = openRouter.getParameters().getTopP();

            LOG.debug("Streaming post-card selection greeting");
            return openRouterClient.streamChatCompletion(request);

        } catch (Exception e) {
            LOG.error("Error generating post-card selection greeting stream", e);
            return Flux.error(e);
        }
    }

    /**
     * Build chat messages with context bridging for Phase 2 streaming.
     * Includes tool results guidance and always includes card data since users can see all cards in UI.
     */
    private List<OpenRouterClient.ChatCompletionRequest.Message> buildChatMessagesWithContext(String userMessage, List<String> conversationHistory, boolean hasCardsSelected, String sessionStatus, List<TarotCardData> cardData, List<AITool.ToolResult> toolResults) {
        List<OpenRouterClient.ChatCompletionRequest.Message> messages = new ArrayList<>();

        // Use state-specific prompt - this is crucial for focused behavior
        String systemPrompt = tarotPrompts.getStateSpecificPrompt(sessionStatus);
        LOG.debug("Using state-specific prompt for session status: {} (prompt length: {} chars)", sessionStatus, systemPrompt.length());

        messages.add(new OpenRouterClient.ChatCompletionRequest.Message("system", systemPrompt));

        // Add conversation history for context
        if (conversationHistory != null && !conversationHistory.isEmpty()) {
            for (String historicalMessage : conversationHistory) {
                // Parse the historical message format "User: message" or "AI: message"
                if (historicalMessage.startsWith("User: ")) {
                    String content = historicalMessage.substring(6); // Remove "User: " prefix
                    messages.add(new OpenRouterClient.ChatCompletionRequest.Message("user", content));
                } else if (historicalMessage.startsWith("AI: ")) {
                    String content = historicalMessage.substring(4); // Remove "AI: " prefix
                    messages.add(new OpenRouterClient.ChatCompletionRequest.Message("assistant", content));
                }
                // Skip any malformed messages
            }
        }

        // Context Bridging: Add tool result context if any tools were called in Phase 1
        if (toolResults != null && !toolResults.isEmpty()) {
            StringBuilder toolContext = new StringBuilder("IMPORTANT - Phase 1 Analysis Results:\n");
            for (AITool.ToolResult result : toolResults) {
                if (result.isSuccess()) {
                    String toolName = result.getMessage();
                    toolContext.append("- ").append(toolName).append(" was called successfully\n");
                    // Add specific guidance based on the tool called
                    switch (toolName) {
                        case "start_interpretation" -> toolContext.append("  → The user provided detailed context. Button will appear automatically. DO NOT interpret cards yet.\n");
                        case "reveal_card" -> toolContext.append("  → Card will be revealed in UI. Focus on interpretation only.\n");
                        case "complete_reading" -> toolContext.append("  → Reading will be marked complete. Provide summary.\n");
                    }
                }
            }
            toolContext.append("\nBased on these tool calls, provide ONLY the appropriate conversational response for your current state.");
            messages.add(new OpenRouterClient.ChatCompletionRequest.Message("system", toolContext.toString()));
        }

        // Only include specific card data for the current interpretation state (prevent bias and confusion)
        if (cardData != null && !cardData.isEmpty() && shouldIncludeCardData(sessionStatus)) {
            String currentCardPosition = getCardPositionFromStatus(sessionStatus);
            if (currentCardPosition != null) {
                // Find and include only the card for the current position being interpreted
                TarotCardData currentCard = cardData.stream()
                    .filter(card -> currentCardPosition.equals(card.getPosition()))
                    .findFirst()
                    .orElse(null);

                if (currentCard != null) {
                    StringBuilder cardInfo = new StringBuilder("Card to interpret for this response:\n");
                    cardInfo.append("- ").append(currentCard.getPosition()).append(": ")
                           .append(currentCard.getName())
                           .append(currentCard.isReversed() ? " (Reversed)" : "")
                           .append("\n");
                    messages.add(new OpenRouterClient.ChatCompletionRequest.Message("system", cardInfo.toString()));
                    LOG.debug("Added {} card data to context for interpretation", currentCardPosition);
                } else {
                    LOG.warn("Could not find {} card in card data for interpretation", currentCardPosition);
                }
            } else {
                // For READING_COMPLETE state, include all cards for summary
                StringBuilder cardInfo = new StringBuilder("All cards from this reading:\n");
                for (TarotCardData card : cardData) {
                    cardInfo.append("- ").append(card.getPosition()).append(": ")
                           .append(card.getName())
                           .append(card.isReversed() ? " (Reversed)" : "")
                           .append("\n");
                }
                messages.add(new OpenRouterClient.ChatCompletionRequest.Message("system", cardInfo.toString()));
                LOG.debug("Added all card data to context for reading completion");
            }
        } else if (cardData != null && !cardData.isEmpty()) {
            LOG.debug("Card data hidden from AI for state: {} to prevent interpretation bias", sessionStatus);
        }

        // Add the current user message
        messages.add(new OpenRouterClient.ChatCompletionRequest.Message("user", userMessage));

        LOG.debug("Built context-bridged chat messages with {} total messages", messages.size());
        return messages;
    }

    private List<OpenRouterClient.ChatCompletionRequest.Message> buildChatMessages(String userMessage, List<String> conversationHistory, boolean hasCardsSelected, String sessionStatus) {
        List<OpenRouterClient.ChatCompletionRequest.Message> messages = new ArrayList<>();

        // Use state-specific prompt if session status is provided, session status should not be null
        String systemPrompt;
        systemPrompt = tarotPrompts.getStateSpecificPrompt(sessionStatus);
        LOG.debug("Using state-specific prompt for session status: {} (prompt length: {} chars)", sessionStatus, systemPrompt.length());

        messages.add(new OpenRouterClient.ChatCompletionRequest.Message("system", systemPrompt));

        // Add conversation history for context
        if (conversationHistory != null && !conversationHistory.isEmpty()) {
            for (String historicalMessage : conversationHistory) {
                // Parse the historical message format "User: message" or "AI: message"
                if (historicalMessage.startsWith("User: ")) {
                    String content = historicalMessage.substring(6); // Remove "User: " prefix
                    messages.add(new OpenRouterClient.ChatCompletionRequest.Message("user", content));
                } else if (historicalMessage.startsWith("AI: ")) {
                    String content = historicalMessage.substring(4); // Remove "AI: " prefix
                    messages.add(new OpenRouterClient.ChatCompletionRequest.Message("assistant", content));
                }
                // Skip any malformed messages
            }
        }

        // Add the current user message
        messages.add(new OpenRouterClient.ChatCompletionRequest.Message("user", userMessage));

        LOG.debug("Built chat messages with {} total messages (including system prompt)", messages.size());
        return messages;
    }

    private String callAI(List<OpenRouterClient.ChatCompletionRequest.Message> messages, boolean isReading) {
        try {
            ApplicationProperties.OpenRouter openRouter = applicationProperties.getOpenrouter();
            String model = openRouter.getModel().getPrimary();

            OpenRouterClient.ChatCompletionRequest request = new OpenRouterClient.ChatCompletionRequest();
            request.model = model;
            request.messages = messages;
            request.temperature = openRouter.getParameters().getTemperature();
            request.maxTokens = isReading ? 1500 : openRouter.getParameters().getMaxTokens(); // More tokens for readings
            request.topP = openRouter.getParameters().getTopP();

            LOG.debug("Calling AI with model: {} for {}", model, isReading ? "tarot reading" : "chat");

            OpenRouterClient.ChatCompletionResponse result = openRouterClient.createChatCompletion(request);

            if (result.choices != null && !result.choices.isEmpty()) {
                String response = result.choices.get(0).message.content;
                LOG.debug("AI response received: {} characters", response.length());
                return response;
            } else {
                throw new RuntimeException("No response from AI model");
            }

        } catch (Exception e) {
            LOG.warn("Primary model failed, trying fallback model", e);
            return callAIWithFallback(messages, isReading);
        }
    }

    private String callAIWithFallback(List<OpenRouterClient.ChatCompletionRequest.Message> messages, boolean isReading) {
        try {
            ApplicationProperties.OpenRouter openRouter = applicationProperties.getOpenrouter();
            String fallbackModel = openRouter.getModel().getFallback();

            OpenRouterClient.ChatCompletionRequest request = new OpenRouterClient.ChatCompletionRequest();
            request.model = fallbackModel;
            request.messages = messages;
            request.temperature = openRouter.getParameters().getTemperature();
            request.maxTokens = isReading ? 1500 : openRouter.getParameters().getMaxTokens();
            request.topP = openRouter.getParameters().getTopP();

            LOG.debug("Calling fallback AI model: {}", fallbackModel);

            OpenRouterClient.ChatCompletionResponse result = openRouterClient.createChatCompletion(request);

            if (result.choices != null && !result.choices.isEmpty()) {
                return result.choices.get(0).message.content;
            } else {
                throw new RuntimeException("No response from fallback AI model");
            }

        } catch (Exception e) {
            LOG.error("Both primary and fallback AI models failed", e);
            throw new RuntimeException("AI service temporarily unavailable", e);
        }
    }


    /**
     * Call AI with tool support.
     */
    private AIResponse callAIWithTools(List<OpenRouterClient.ChatCompletionRequest.Message> messages, boolean isReading) {
        return callAIWithTools(messages, isReading, null);
    }

    /**
     * Call AI with tool support and session state validation.
     */
    private AIResponse callAIWithTools(List<OpenRouterClient.ChatCompletionRequest.Message> messages, boolean isReading, String sessionStatus) {
        try {
            ApplicationProperties.OpenRouter openRouter = applicationProperties.getOpenrouter();
            String model = openRouter.getModel().getPrimary();

            OpenRouterClient.ChatCompletionRequest request = new OpenRouterClient.ChatCompletionRequest();
            request.model = model;
            request.messages = messages;
            request.temperature = openRouter.getParameters().getTemperature();
            request.maxTokens = isReading ? 1500 : openRouter.getParameters().getMaxTokens();
            request.topP = openRouter.getParameters().getTopP();
            request.stream = false; // Ensure streaming is disabled for tool calls

            if (!isReading && toolManager.hasTools()) {
                request.tools = new ArrayList<>(toolManager.getToolsForApiCall());
                request.toolChoice = "auto"; // Let AI decide when to use tools
                LOG.debug("Added {} tools to AI request", toolManager.getToolCount());
            }

            LOG.debug("Calling AI with model: {} for {} (session status: {})", model, isReading ? "tarot reading" : "chat", sessionStatus);

            OpenRouterClient.ChatCompletionResponse result = openRouterClient.createChatCompletion(request);

            if (result.choices != null && !result.choices.isEmpty()) {
                OpenRouterClient.ChatCompletionResponse.Choice.Message message = result.choices.get(0).message;

                // Check for tool calls - now with session state validation
                List<AITool.ToolResult> toolResults = null;
                if (message.toolCalls != null && !message.toolCalls.isEmpty()) {
                    toolResults = processToolCalls(message.toolCalls, sessionStatus);
                }

                String response = message.content != null ? message.content : "";
                LOG.debug("AI response received: {} characters, {} tool calls",
                    response.length(),
                    toolResults != null ? toolResults.size() : 0);

                return new AIResponse(response, toolResults);
            } else {
                throw new RuntimeException("No response from AI model");
            }

        } catch (Exception e) {
            LOG.warn("Primary model failed, trying fallback model", e);
            // For fallback, we don't include tools
            String response = callAIWithFallback(messages, isReading);
            return new AIResponse(response, null);
        }
    }


    /**
     * Process tool calls from AI response.
     */
    private List<AITool.ToolResult> processToolCalls(List<OpenRouterClient.ChatCompletionResponse.Choice.Message.ToolCall> toolCalls) {
        return processToolCalls(toolCalls, null);
    }

    /**
     * Process tool calls from AI response with session state validation.
     */
    private List<AITool.ToolResult> processToolCalls(List<OpenRouterClient.ChatCompletionResponse.Choice.Message.ToolCall> toolCalls, String sessionStatus) {
        List<AITool.ToolResult> results = new ArrayList<>();

        for (OpenRouterClient.ChatCompletionResponse.Choice.Message.ToolCall toolCall : toolCalls) {
            try {
                String toolName = toolCall.function.name;
                String argumentsJson = toolCall.function.arguments;

                LOG.info("Processing tool call: {} with arguments: {}", toolName, argumentsJson);

                // CRITICAL: Validate session state before executing tools
                AITool.ToolResult validationResult = validateToolForSessionState(toolName, sessionStatus);
                if (validationResult != null) {
                    LOG.warn("Tool call validation failed for {}: {}", toolName, validationResult.getMessage());
                    results.add(validationResult);
                    continue;
                }

                // Parse arguments
                Map<String, Object> arguments = objectMapper.readValue(argumentsJson, Map.class);

                // Execute tool
                AITool.ToolResult result = toolManager.executeTool(toolName, arguments);
                results.add(result);

            } catch (Exception e) {
                LOG.error("Error processing tool call", e);
                results.add(AITool.ToolResult.failure("Error processing tool: " + e.getMessage()));
            }
        }

        return results;
    }

    /**
     * Validate if a tool can be called in the current session state.
     * Returns null if valid, or ToolResult with error if invalid.
     */
    private AITool.ToolResult validateToolForSessionState(String toolName, String sessionStatus) {
        if (sessionStatus == null) {
            return null; // Allow if no session status available
        }

        switch (toolName) {
            case "start_interpretation" -> {
                if (!"AWAITING_USER_CONTEXT".equals(sessionStatus)) {
                    return AITool.ToolResult.failure(
                        "start_interpretation tool called in wrong state: " + sessionStatus +
                        ". This tool is only valid in AWAITING_USER_CONTEXT state."
                    );
                }
            }
            case "reveal_card" -> {
                if (!("AWAITING_SITUATION".equals(sessionStatus) ||
                      "AWAITING_OBSTACLE".equals(sessionStatus) ||
                      "AWAITING_ADVICE".equals(sessionStatus))) {
                    return AITool.ToolResult.failure(
                        "reveal_card tool called in wrong state: " + sessionStatus +
                        ". This tool is only valid in AWAITING_SITUATION, AWAITING_OBSTACLE, or AWAITING_ADVICE states."
                    );
                }
            }
            case "complete_reading" -> {
                if (!"AWAITING_ADVICE".equals(sessionStatus) && !"READING_COMPLETE".equals(sessionStatus)) {
                    return AITool.ToolResult.failure(
                        "complete_reading tool called in wrong state: " + sessionStatus +
                        ". This tool is only valid in AWAITING_ADVICE or READING_COMPLETE states."
                    );
                }
            }
            // Other tools don't have state restrictions
            default -> {
                // Allow all other tools
            }
        }

        return null; // Valid
    }

    /**
     * Determine if card data should be included based on session status.
     * Only include card data when AI needs to interpret them (prevent bias in other states).
     */
    private boolean shouldIncludeCardData(String sessionStatus) {
        return sessionStatus != null && (
            "AWAITING_SITUATION".equals(sessionStatus) ||
            "AWAITING_OBSTACLE".equals(sessionStatus) ||
            "AWAITING_ADVICE".equals(sessionStatus) ||
            "READING_COMPLETE".equals(sessionStatus)
        );
    }

    /**
     * Get the card position that should be interpreted based on session status.
     */
    private String getCardPositionFromStatus(String sessionStatus) {
        return switch (sessionStatus) {
            case "AWAITING_SITUATION" -> "situation";
            case "AWAITING_OBSTACLE" -> "obstacle";
            case "AWAITING_ADVICE" -> "advice";
            default -> null; // For READING_COMPLETE or other states
        };
    }

    /**
     * Generate a structured, parseable interpretation for a specific card position.
     * This method creates clean interpretations separate from conversational flow.
     *
     * @param card The card to interpret
     * @param cardPosition The position in the spread (situation, obstacle, advice)
     * @param userContext The user's specific context and situation
     * @return Clean, structured interpretation text
     */
    public String generateStructuredCardInterpretation(TarotCardData card, String cardPosition, String userContext) {
        try {
            List<OpenRouterClient.ChatCompletionRequest.Message> messages = new ArrayList<>();

            // Create a focused system prompt for structured interpretation generation
            String systemPrompt = """
                You are a professional tarot reader generating a clean, structured interpretation for a specific card.

                Your task is to provide a focused interpretation that:
                1. Connects the card's meaning to the user's specific context
                2. Uses Jungian psychology and astrological correspondences appropriately
                3. Is clear, direct, and easy to parse
                4. Focuses on practical insights and empowerment

                Format your response as a coherent interpretation paragraph (not bullets or lists).
                Keep it concise but meaningful (2-4 sentences maximum).
                Make it accessible - no academic jargon.
                """;

            messages.add(new OpenRouterClient.ChatCompletionRequest.Message("system", systemPrompt));

            // Build focused interpretation prompt
            StringBuilder interpretationPrompt = new StringBuilder();
            interpretationPrompt.append("Generate a structured interpretation for:\n\n");
            interpretationPrompt.append("Card: ").append(card.getName());
            if (card.isReversed()) {
                interpretationPrompt.append(" (Reversed)");
            }
            interpretationPrompt.append("\n");
            interpretationPrompt.append("Position: ").append(cardPosition).append("\n");
            interpretationPrompt.append("User Context: ").append(userContext).append("\n\n");

            // Add position-specific guidance
            switch (cardPosition.toLowerCase()) {
                case "situation" -> interpretationPrompt.append("Focus on: Current state, underlying energies, what the user needs to understand about their present circumstances.");
                case "obstacle" -> interpretationPrompt.append("Focus on: Challenges to overcome, shadow work, hidden barriers, what needs to be addressed or integrated.");
                case "advice" -> interpretationPrompt.append("Focus on: Practical guidance, empowering action steps, how to move forward with wisdom and confidence.");
            }

            interpretationPrompt.append("\n\nProvide a clean, structured interpretation that connects this card's wisdom to their specific situation.");

            messages.add(new OpenRouterClient.ChatCompletionRequest.Message("user", interpretationPrompt.toString()));

            // Call AI with focused interpretation request
            String interpretation = callAI(messages, true);

            LOG.debug("Generated structured interpretation for {} card: {} characters", cardPosition, interpretation.length());
            return interpretation;

        } catch (Exception e) {
            LOG.error("Error generating structured card interpretation for {} position", cardPosition, e);
            // Return fallback interpretation
            return generateFallbackInterpretation(card, cardPosition, userContext);
        }
    }

    /**
     * Generate a fallback interpretation when AI call fails.
     */
    private String generateFallbackInterpretation(TarotCardData card, String cardPosition, String userContext) {
        StringBuilder fallback = new StringBuilder();
        fallback.append("The ").append(card.getName());
        if (card.isReversed()) {
            fallback.append(" (Reversed)");
        }
        fallback.append(" in the ").append(cardPosition).append(" position suggests ");

        switch (cardPosition.toLowerCase()) {
            case "situation" -> fallback.append("important energies surrounding your current circumstances");
            case "obstacle" -> fallback.append("challenges that need your attention and wisdom to overcome");
            case "advice" -> fallback.append("guidance for moving forward with clarity and purpose");
            default -> fallback.append("meaningful insights for your journey");
        }

        fallback.append(". Consider how this card's energy relates to your specific situation and what actions it might inspire.");

        return fallback.toString();
    }

    /**
     * Build a basic summary without AI assistance (fallback).
     */
    private String buildBasicSummary(List<TarotCardData> selectedCards) {
        StringBuilder summary = new StringBuilder();
        summary.append("Tarot reading performed with ");
        summary.append(selectedCards.size()).append(" cards: ");

        for (int i = 0; i < selectedCards.size(); i++) {
            TarotCardData card = selectedCards.get(i);
            if (i > 0) summary.append(", ");
            summary.append(card.getName());
            summary.append(" (").append(card.getPosition()).append(")");
            if (card.isReversed()) summary.append(" reversed");
        }

        summary.append(". Full interpretation was provided to guide the querent.");
        return summary.toString();
    }

    /**
     * Build a basic greeting without AI assistance (fallback).
     */
    private String buildBasicGreeting(List<TarotCardData> selectedCards) {
        StringBuilder greeting = new StringBuilder();
        greeting.append("Wonderful! I can see you've drawn ");
        greeting.append(selectedCards.size()).append(" cards for your reading: ");

        for (int i = 0; i < selectedCards.size(); i++) {
            TarotCardData card = selectedCards.get(i);
            if (i > 0) greeting.append(", ");
            greeting.append("the ").append(card.getName());
            greeting.append(" for your ").append(card.getPosition());
            if (card.isReversed()) greeting.append(" (reversed)");
        }

        greeting.append(". These cards have found their way to you for a reason. Take a moment to reflect on your question, and when you're ready, I'll guide you through their deeper meanings.");
        return greeting.toString();
    }

    /**
     * Analyze conversation for UI actions using a separate, non-streaming call.
     * This is Phase 2 of the two-phase approach for robust tool calling.
     *
     * @param userMessage The user's message
     * @param conversationHistory Previous messages in the conversation
     * @param hasCardsSelected Whether the session has cards selected
     * @param selectedCards The actual card data if available
     * @param sessionStatus The current session status for state-specific prompts
     * @return AI response with tool calls for UI control
     */
    public AIResponse analyzeForUIActions(String userMessage, List<String> conversationHistory, boolean hasCardsSelected, List<TarotCardData> selectedCards, String sessionStatus) {
        try {
            LOG.info("analyzeForUIActions called with userMessage: '{}', hasCardsSelected: {}", userMessage, hasCardsSelected);

            List<OpenRouterClient.ChatCompletionRequest.Message> messages = buildChatMessages(userMessage, conversationHistory, hasCardsSelected, sessionStatus);

            // Only include specific card data for the current interpretation state (prevent bias in tool analysis)
            if (selectedCards != null && !selectedCards.isEmpty() && shouldIncludeCardData(sessionStatus)) {
                String currentCardPosition = getCardPositionFromStatus(sessionStatus);
                if (currentCardPosition != null) {
                    // Find and include only the card for the current position being interpreted
                    TarotCardData currentCard = selectedCards.stream()
                        .filter(card -> currentCardPosition.equals(card.getPosition()))
                        .findFirst()
                        .orElse(null);

                    if (currentCard != null) {
                        StringBuilder cardInfo = new StringBuilder("Card to analyze for interpretation:\n");
                        cardInfo.append("- ").append(currentCard.getPosition()).append(": ")
                               .append(currentCard.getName())
                               .append(currentCard.isReversed() ? " (Reversed)" : "")
                               .append("\n");
                        messages.add(new OpenRouterClient.ChatCompletionRequest.Message("system", cardInfo.toString()));
                        LOG.debug("Added {} card data to tool analysis for interpretation", currentCardPosition);
                    } else {
                        LOG.warn("Could not find {} card in card data for tool analysis", currentCardPosition);
                    }
                } else {
                    // For READING_COMPLETE state, include all cards for summary analysis
                    StringBuilder cardInfo = new StringBuilder("All cards from this reading:\n");
                    for (TarotCardData card : selectedCards) {
                        cardInfo.append("- ").append(card.getPosition()).append(": ")
                               .append(card.getName())
                               .append(card.isReversed() ? " (Reversed)" : "")
                               .append("\n");
                    }
                    messages.add(new OpenRouterClient.ChatCompletionRequest.Message("system", cardInfo.toString()));
                    LOG.debug("Added all card data to tool analysis for reading completion");
                }
            } else if (selectedCards != null && !selectedCards.isEmpty()) {
                LOG.debug("Card data hidden from tool analysis for state: {} to prevent interpretation bias", sessionStatus);
            }

            // For the special trigger message, don't add extra instructions
            if (!"I'm ready to begin my reading interpretation.".equals(userMessage)) {
                // Add a specific instruction for UI analysis
                messages.add(new OpenRouterClient.ChatCompletionRequest.Message("user",
                    "Based on the conversation above, analyze if any UI tools should be called. " +
                    "This is a separate analysis phase - do not provide conversational text, " +
                    "only determine if tools like start_interpretation, reveal_card, or complete_reading should be called."));
            }

            return callAIWithTools(messages, false, sessionStatus);
        } catch (Exception e) {
            LOG.error("Error analyzing for UI actions", e);
            return new AIResponse("", null);
        }
    }
}
