"""Message classification for detecting user intent and satisfaction signals."""

from __future__ import annotations

import re
from promethian.core.types import MessageType, SatisfactionType
from promethian.utils.claude import ClaudeClient


# Quick patterns for common cases (skip LLM call)
POSITIVE_PATTERNS = [
    r'\b(thanks?|thank\s*you|thx|ty)\b',
    r'\b(perfect|excellent|great|awesome|amazing|wonderful)\b',
    r'\b(works?|worked|working)\b.*\b(great|perfect|well)\b',
    r'^(nice|cool|sweet|neat)[\s!.]*$',
    r'\bgood\s*job\b',
    r'\bthat\'?s?\s*(it|exactly|right|correct)\b',
]

NEGATIVE_PATTERNS = [
    r'\b(wrong|incorrect|error|mistake)\b',
    r'\b(doesn\'?t?|don\'?t|didn\'?t)\s*(work|help)\b',
    r'\b(no|nope),?\s*(that\'?s?|it\'?s?)?\s*(not|wrong)\b',
    r'\btry\s*again\b',
    r'\b(bad|terrible|awful|useless)\b',
]

REFINEMENT_PATTERNS = [
    r'\b(no|actually|wait),?\s*(i\s*)?(meant?|want)\b',
    r'\b(instead|rather)\b',
    r'\bnot\s+(what|that)\s+(i|we)\s+(meant?|want)\b',
    r'\blet\s*me\s*(clarify|rephrase|explain)\b',
    r'\bi\s*should\s*have\s*(said|mentioned)\b',
]

FOLLOW_UP_PATTERNS = [
    r'\b(now|next|also|and)\s*(can\s*you|please|could)\b',
    r'\b(one\s*more|another)\s*(thing|question|task)\b',
    r'\bwhat\s*about\b',
    r'\bhow\s*about\b',
    r'\badd(itionally)?\b',
    r'\bcan\s*you\s*also\b',
]

CLOSE_PATTERNS = [
    r'\b(bye|goodbye|done|finished|that\'?s?\s*all)\b',
    r'\b(exit|quit|close|end)\s*(session)?\b',
    r'\bi\'?m\s*(done|finished|good)\b',
    r'^(ok|okay|k)[\s!.]*$',
]


def _check_patterns(text: str, patterns: list[str]) -> bool:
    """Check if text matches any pattern."""
    text_lower = text.lower().strip()
    for pattern in patterns:
        if re.search(pattern, text_lower, re.IGNORECASE):
            return True
    return False


def quick_classify(text: str) -> MessageType | None:
    """
    Quick pattern-based classification for obvious cases.
    Returns None if uncertain (needs LLM).
    """
    text = text.strip()

    # Very short positive feedback
    if len(text) < 50:
        if _check_patterns(text, POSITIVE_PATTERNS):
            return MessageType.POSITIVE_FEEDBACK
        if _check_patterns(text, CLOSE_PATTERNS):
            return MessageType.CLOSE_SESSION

    # Check negative patterns
    if _check_patterns(text, NEGATIVE_PATTERNS):
        return MessageType.NEGATIVE_FEEDBACK

    # Check refinement patterns
    if _check_patterns(text, REFINEMENT_PATTERNS):
        return MessageType.REFINEMENT

    # Check follow-up patterns
    if _check_patterns(text, FOLLOW_UP_PATTERNS):
        return MessageType.FOLLOW_UP

    return None  # Needs LLM classification


class MessageClassifier:
    """Classifies user messages to detect intent and satisfaction signals."""

    def __init__(self, claude: ClaudeClient):
        self.claude = claude

    async def classify(
        self,
        message: str,
        conversation_context: str | None = None,
        is_first_message: bool = False,
    ) -> tuple[MessageType, float]:
        """
        Classify a user message.

        Args:
            message: The user's message text
            conversation_context: Previous conversation for context
            is_first_message: Whether this is the first message in session

        Returns:
            Tuple of (MessageType, confidence 0-1)
        """
        # First message is always initial request
        if is_first_message:
            return MessageType.INITIAL_REQUEST, 1.0

        # Try quick pattern matching first
        quick_result = quick_classify(message)
        if quick_result is not None:
            return quick_result, 0.9  # High confidence for pattern matches

        # Use LLM for uncertain cases
        return await self._llm_classify(message, conversation_context)

    async def _llm_classify(
        self,
        message: str,
        conversation_context: str | None,
    ) -> tuple[MessageType, float]:
        """Use LLM to classify message."""

        context_section = ""
        if conversation_context:
            context_section = f"""
Recent conversation:
{conversation_context}

"""

        prompt = f"""{context_section}New user message: "{message}"

Classify this message into exactly ONE of these categories:

1. POSITIVE_FEEDBACK - User expressing satisfaction (thanks, great, perfect, that works)
2. NEGATIVE_FEEDBACK - User expressing dissatisfaction (wrong, doesn't work, that's not right)
3. FOLLOW_UP - User asking for more based on previous output (now do X, also..., what about...)
4. REFINEMENT - User correcting or clarifying (no I meant..., actually..., let me rephrase)
5. CLARIFICATION - User answering a question you asked
6. NEW_REQUEST - Completely unrelated new task
7. CLOSE_SESSION - User indicating they're done (bye, that's all, I'm done)

Respond with just the category name (e.g., "POSITIVE_FEEDBACK")."""

        response = await self.claude.message(
            prompt,
            max_tokens=50,
            system="You are a message classifier. Respond with only the category name, nothing else.",
        )

        # Parse response
        response_text = response.strip().upper().replace(" ", "_")

        # Map to MessageType
        type_map = {
            "POSITIVE_FEEDBACK": MessageType.POSITIVE_FEEDBACK,
            "NEGATIVE_FEEDBACK": MessageType.NEGATIVE_FEEDBACK,
            "FOLLOW_UP": MessageType.FOLLOW_UP,
            "REFINEMENT": MessageType.REFINEMENT,
            "CLARIFICATION": MessageType.CLARIFICATION,
            "NEW_REQUEST": MessageType.NEW_REQUEST,
            "CLOSE_SESSION": MessageType.CLOSE_SESSION,
        }

        msg_type = type_map.get(response_text, MessageType.NEW_REQUEST)
        return msg_type, 0.8  # Slightly lower confidence for LLM classification

    def get_satisfaction_signal(
        self,
        message_type: MessageType,
        confidence: float,
    ) -> tuple[SatisfactionType, float] | None:
        """
        Convert a message type to a satisfaction signal if applicable.

        Returns:
            Tuple of (SatisfactionType, signal_confidence) or None
        """
        signal_map = {
            MessageType.POSITIVE_FEEDBACK: SatisfactionType.EXPLICIT_POSITIVE,
            MessageType.NEGATIVE_FEEDBACK: SatisfactionType.EXPLICIT_NEGATIVE,
            MessageType.FOLLOW_UP: SatisfactionType.IMPLICIT_POSITIVE_FOLLOW_UP,
            MessageType.REFINEMENT: SatisfactionType.IMPLICIT_NEGATIVE_REFINEMENT,
            MessageType.CLOSE_SESSION: SatisfactionType.IMPLICIT_POSITIVE_CLOSE,
        }

        signal_type = signal_map.get(message_type)
        if signal_type:
            return signal_type, confidence

        return None

    def references_prior_output(self, message: str, prior_output: str | None) -> bool:
        """
        Check if the message references prior assistant output.

        This is an implicit positive signal - user is engaging with the output.
        """
        if not prior_output:
            return False

        message_lower = message.lower()

        # Check for pronouns referring to prior output
        reference_words = ["it", "this", "that", "these", "those", "the output", "the result"]
        has_reference = any(word in message_lower for word in reference_words)

        # Check for quoted content from prior output
        # (If user quotes back something from output, they're engaging)
        if len(prior_output) > 20:
            # Check for any 10+ char substring match
            for i in range(0, min(len(prior_output) - 10, 200), 5):
                snippet = prior_output[i:i+10].lower()
                if snippet in message_lower:
                    return True

        return has_reference
