"""
AI Self-Aware Worthiness Judgment System.

Implements intelligent filtering to determine which knowledge should be stored
based on AI's self-awareness of its blind spots and common sense boundaries.

Core Philosophy:
AI should only store knowledge that will improve future conversation quality.
This requires AI to understand:
1. What AI already knows (common sense)
2. What AI doesn't know well (blind spots)
3. How much improvement storing this knowledge would bring

Key Question: "Will storing this knowledge make future conversations better?"
"""

from typing import Dict, Any, Optional, Tuple, List
from dataclasses import dataclass
from enum import Enum
import re

from .ai_knowledge_taxonomy import (
    classify_knowledge_boundaries,
    AIBlindSpotsTaxonomy,
    AICommonSenseTaxonomy
)


class WorthinessDecision(Enum):
    """Final worthiness decision."""
    STORE = "store"              # Definitely store
    SKIP = "skip"                # Don't store
    UNCERTAIN = "uncertain"      # Need user confirmation
    CONDITIONAL = "conditional"  # Store only if user insists


@dataclass
class ConversationQualityImpact:
    """
    Impact on conversation quality dimensions.
    All scores are 0.0-1.0, representing improvement potential.
    """
    accuracy: float       # Will reduce mistakes and errors
    efficiency: float     # Will speed up task completion
    personalization: float  # Will better match user preferences
    proactiveness: float  # Will anticipate needs
    consistency: float    # Will maintain quality across conversations
    learning: float       # Will avoid repeating mistakes

    def overall_score(self) -> float:
        """Calculate overall CQI score (weighted average)."""
        weights = {
            'accuracy': 0.30,        # Most important - correctness
            'efficiency': 0.20,      # Time savings
            'personalization': 0.20, # User satisfaction
            'proactiveness': 0.10,   # Anticipation
            'consistency': 0.10,     # Reliability
            'learning': 0.10         # Continuous improvement
        }

        total = (
            self.accuracy * weights['accuracy'] +
            self.efficiency * weights['efficiency'] +
            self.personalization * weights['personalization'] +
            self.proactiveness * weights['proactiveness'] +
            self.consistency * weights['consistency'] +
            self.learning * weights['learning']
        )

        return round(total, 2)


class WorthinessFilter:
    """
    AI Self-Aware Worthiness Judgment System.

    Determines whether knowledge is worth storing by evaluating:
    1. Is this AI's blind spot or common sense?
    2. How much will this improve conversation quality?
    3. What are the edge cases and special conditions?
    """

    # Thresholds for decision making
    THRESHOLD_DEFINITELY_STORE = 0.70
    THRESHOLD_LIKELY_STORE = 0.50
    THRESHOLD_UNCERTAIN = 0.30
    THRESHOLD_SKIP = 0.30

    def __init__(self):
        """Initialize worthiness filter."""
        self.blind_spots_taxonomy = AIBlindSpotsTaxonomy()
        self.common_sense_taxonomy = AICommonSenseTaxonomy()

    def is_worth_storing(
        self,
        content: str,
        context: Optional[Dict[str, Any]] = None
    ) -> Tuple[WorthinessDecision, str, float]:
        """
        Main entry point: Determine if knowledge is worth storing.

        Args:
            content: Knowledge content to evaluate
            context: Optional context (source, user_explicit, etc.)

        Returns:
            Tuple of:
            - WorthinessDecision: Final decision
            - str: Human-readable reasoning
            - float: Confidence score (0.0-1.0)

        Philosophy:
        - AI blind spots → likely worth storing
        - AI common sense → likely not worth storing
        - High CQI score → worth storing
        - User explicit request → always honor (even if trivial)
        """
        if not content or not content.strip():
            return (WorthinessDecision.SKIP, "Empty content", 1.0)

        context = context or {}

        # Step 1: Check for explicit user request
        if self._is_explicit_user_request(content, context):
            return (
                WorthinessDecision.STORE,
                "User explicitly requested storage",
                0.99
            )

        # Step 2: Classify knowledge boundaries
        boundary_classification = classify_knowledge_boundaries(content)

        # Step 3: Evaluate conversation quality improvement
        cqi = self._evaluate_conversation_quality_improvement(
            content,
            boundary_classification,
            context
        )

        # Step 4: Apply decision rules
        decision, reasoning, confidence = self._make_decision(
            boundary_classification,
            cqi,
            context
        )

        return (decision, reasoning, confidence)

    def _is_explicit_user_request(
        self,
        content: str,
        context: Dict[str, Any]
    ) -> bool:
        """
        Check if user explicitly requested to remember this.

        Indicators:
        - Context flag: user_explicit=True
        - Keywords: "remember", "note", "keep in mind", "don't forget"
        - Phrases: "save this", "store this", "I want you to remember"
        """
        # Check context flag
        if context.get('user_explicit', False):
            return True

        # Check content for explicit request keywords
        content_lower = content.lower()
        explicit_keywords = [
            'remember',
            'note that',
            'keep in mind',
            "don't forget",
            'save this',
            'store this',
            'i want you to remember',
            'make a note',
            'record this'
        ]

        return any(keyword in content_lower for keyword in explicit_keywords)

    def _evaluate_conversation_quality_improvement(
        self,
        content: str,
        boundary_classification: Dict[str, Any],
        context: Dict[str, Any]
    ) -> ConversationQualityImpact:
        """
        Evaluate how much storing this knowledge would improve conversation quality.

        Returns:
            ConversationQualityImpact with scores for each dimension
        """
        classification = boundary_classification['classification']
        confidence = boundary_classification['confidence']

        # Base scores on classification
        if classification == 'blind_spot':
            base_accuracy = 0.8 * confidence
            base_efficiency = 0.7 * confidence
            base_personalization = 0.6 * confidence
            base_proactiveness = 0.6 * confidence
            base_consistency = 0.7 * confidence
            base_learning = 0.8 * confidence

        elif classification == 'common_sense':
            base_accuracy = 0.1
            base_efficiency = 0.1
            base_personalization = 0.1
            base_proactiveness = 0.1
            base_consistency = 0.1
            base_learning = 0.1

        else:  # uncertain
            base_accuracy = 0.4
            base_efficiency = 0.4
            base_personalization = 0.4
            base_proactiveness = 0.3
            base_consistency = 0.4
            base_learning = 0.4

        # Apply specific category boosts
        category = boundary_classification.get('category', '')

        # User corrections → huge accuracy boost
        if 'correction' in category:
            base_accuracy = min(base_accuracy + 0.3, 1.0)
            base_learning = min(base_learning + 0.3, 1.0)

        # User preferences → huge personalization boost
        if 'user_specific' in category or 'preference' in category:
            base_personalization = min(base_personalization + 0.3, 1.0)
            base_proactiveness = min(base_proactiveness + 0.2, 1.0)

        # Project-specific → efficiency boost
        if 'project' in category:
            base_efficiency = min(base_efficiency + 0.2, 1.0)
            base_consistency = min(base_consistency + 0.2, 1.0)

        # Edge cases/traps → accuracy and learning boost
        if 'edge' in category or 'trap' in category or 'gotcha' in category:
            base_accuracy = min(base_accuracy + 0.2, 1.0)
            base_learning = min(base_learning + 0.2, 1.0)

        # Counter-intuitive → accuracy boost
        if 'counter' in category:
            base_accuracy = min(base_accuracy + 0.25, 1.0)

        # Apply context-specific adjustments
        if context.get('user_correction', False):
            base_accuracy = min(base_accuracy + 0.2, 1.0)
            base_learning = min(base_learning + 0.2, 1.0)

        if context.get('repeated_mistake', False):
            base_learning = min(base_learning + 0.3, 1.0)
            base_accuracy = min(base_accuracy + 0.2, 1.0)

        if context.get('critical', False):
            base_accuracy = min(base_accuracy + 0.15, 1.0)
            base_consistency = min(base_consistency + 0.15, 1.0)

        return ConversationQualityImpact(
            accuracy=round(base_accuracy, 2),
            efficiency=round(base_efficiency, 2),
            personalization=round(base_personalization, 2),
            proactiveness=round(base_proactiveness, 2),
            consistency=round(base_consistency, 2),
            learning=round(base_learning, 2)
        )

    def _make_decision(
        self,
        boundary_classification: Dict[str, Any],
        cqi: ConversationQualityImpact,
        context: Dict[str, Any]
    ) -> Tuple[WorthinessDecision, str, float]:
        """
        Make final worthiness decision based on all factors.

        Decision Logic:
        1. CQI score >= 0.70 → STORE (high improvement potential)
        2. CQI score >= 0.50 → STORE (good improvement potential)
        3. CQI score >= 0.30 → UNCERTAIN (need user confirmation)
        4. CQI score < 0.30 → SKIP (low improvement potential)

        Special cases:
        - Blind spot + high confidence → STORE
        - Common sense + low CQI → SKIP
        - User explicit → already handled earlier (always STORE)
        """
        classification = boundary_classification['classification']
        confidence = boundary_classification['confidence']
        category = boundary_classification.get('category', 'unknown')

        cqi_score = cqi.overall_score()

        # Build reasoning string
        reasoning_parts = []

        # Add classification info
        if classification == 'blind_spot':
            reasoning_parts.append(
                f"✓ AI Blind Spot detected: {category} (confidence: {confidence:.2f})"
            )
        elif classification == 'common_sense':
            reasoning_parts.append(
                f"✗ AI Common Sense: {category} (confidence: {confidence:.2f})"
            )
        else:
            reasoning_parts.append(
                f"? Uncertain classification: {category}"
            )

        # Add CQI breakdown
        reasoning_parts.append(
            f"CQI Score: {cqi_score:.2f} "
            f"[Accuracy: {cqi.accuracy:.2f}, "
            f"Efficiency: {cqi.efficiency:.2f}, "
            f"Personalization: {cqi.personalization:.2f}]"
        )

        # Decision logic
        if cqi_score >= self.THRESHOLD_DEFINITELY_STORE:
            reasoning_parts.append(
                f"→ High improvement potential (CQI ≥ {self.THRESHOLD_DEFINITELY_STORE})"
            )
            return (
                WorthinessDecision.STORE,
                " | ".join(reasoning_parts),
                0.90
            )

        elif cqi_score >= self.THRESHOLD_LIKELY_STORE:
            reasoning_parts.append(
                f"→ Good improvement potential (CQI ≥ {self.THRESHOLD_LIKELY_STORE})"
            )
            return (
                WorthinessDecision.STORE,
                " | ".join(reasoning_parts),
                0.75
            )

        elif cqi_score >= self.THRESHOLD_UNCERTAIN:
            # Check if blind spot with decent confidence
            if classification == 'blind_spot' and confidence >= 0.6:
                reasoning_parts.append(
                    "→ Blind spot with decent confidence, recommend storing"
                )
                return (
                    WorthinessDecision.STORE,
                    " | ".join(reasoning_parts),
                    0.65
                )

            reasoning_parts.append(
                f"→ Uncertain - CQI in gray zone ({self.THRESHOLD_UNCERTAIN}-{self.THRESHOLD_LIKELY_STORE})"
            )
            return (
                WorthinessDecision.UNCERTAIN,
                " | ".join(reasoning_parts),
                0.50
            )

        else:  # cqi_score < THRESHOLD_SKIP
            # Check if common sense with high confidence
            if classification == 'common_sense' and confidence >= 0.7:
                reasoning_parts.append(
                    "→ AI already knows this well, no storage needed"
                )
                return (
                    WorthinessDecision.SKIP,
                    " | ".join(reasoning_parts),
                    0.85
                )

            reasoning_parts.append(
                f"→ Low improvement potential (CQI < {self.THRESHOLD_SKIP})"
            )
            return (
                WorthinessDecision.SKIP,
                " | ".join(reasoning_parts),
                0.70
            )

    def explain_decision(
        self,
        content: str,
        context: Optional[Dict[str, Any]] = None
    ) -> str:
        """
        Provide detailed explanation of worthiness decision.

        Useful for transparency and debugging.

        Returns:
            Multi-line detailed explanation
        """
        decision, reasoning, confidence = self.is_worth_storing(content, context)

        # Get detailed analysis
        boundary_classification = classify_knowledge_boundaries(content)
        cqi = self._evaluate_conversation_quality_improvement(
            content,
            boundary_classification,
            context or {}
        )

        lines = [
            "=" * 70,
            "AI SELF-AWARE WORTHINESS JUDGMENT",
            "=" * 70,
            "",
            "DECISION:",
            f"  {decision.value.upper()} (confidence: {confidence:.2f})",
            "",
            "REASONING:",
            f"  {reasoning}",
            "",
            "KNOWLEDGE BOUNDARY CLASSIFICATION:",
            f"  Classification: {boundary_classification['classification']}",
            f"  Category: {boundary_classification['category']}",
            f"  Confidence: {boundary_classification['confidence']:.2f}",
            f"  Reasoning: {boundary_classification['reasoning']}",
            "",
            "CONVERSATION QUALITY IMPROVEMENT (CQI) ANALYSIS:",
            f"  Overall Score: {cqi.overall_score():.2f}",
            f"  ├─ Accuracy (30%):        {cqi.accuracy:.2f}  - Will reduce mistakes",
            f"  ├─ Efficiency (20%):      {cqi.efficiency:.2f}  - Will speed up tasks",
            f"  ├─ Personalization (20%): {cqi.personalization:.2f}  - Will match preferences",
            f"  ├─ Proactiveness (10%):   {cqi.proactiveness:.2f}  - Will anticipate needs",
            f"  ├─ Consistency (10%):     {cqi.consistency:.2f}  - Will maintain quality",
            f"  └─ Learning (10%):        {cqi.learning:.2f}  - Will avoid mistakes",
            "",
            "INTERPRETATION:",
        ]

        # Add interpretation based on decision
        if decision == WorthinessDecision.STORE:
            lines.extend([
                "  ✓ STORE - This knowledge fills an AI blind spot and will improve",
                "    future conversation quality. Storing is recommended.",
            ])
        elif decision == WorthinessDecision.SKIP:
            lines.extend([
                "  ✗ SKIP - This is AI common sense or has low improvement potential.",
                "    Storing would not meaningfully improve conversation quality.",
            ])
        elif decision == WorthinessDecision.UNCERTAIN:
            lines.extend([
                "  ? UNCERTAIN - Classification is ambiguous or improvement potential",
                "    is unclear. Consider asking user for confirmation.",
            ])
        elif decision == WorthinessDecision.CONDITIONAL:
            lines.extend([
                "  ~ CONDITIONAL - Store only if user explicitly requests it.",
                "    AI doesn't see strong value, but respects user judgment.",
            ])

        lines.extend([
            "",
            "=" * 70
        ])

        return "\n".join(lines)

    def batch_evaluate(
        self,
        items: List[Dict[str, Any]]
    ) -> List[Dict[str, Any]]:
        """
        Evaluate worthiness for multiple knowledge items.

        Args:
            items: List of dicts with keys: content, context (optional)

        Returns:
            List of dicts with keys: content, decision, reasoning, confidence, cqi_score
        """
        results = []

        for item in items:
            content = item.get('content', '')
            context = item.get('context')

            decision, reasoning, confidence = self.is_worth_storing(content, context)

            # Get CQI score
            boundary_classification = classify_knowledge_boundaries(content)
            cqi = self._evaluate_conversation_quality_improvement(
                content,
                boundary_classification,
                context or {}
            )

            results.append({
                'content': content,
                'decision': decision.value,
                'reasoning': reasoning,
                'confidence': confidence,
                'cqi_score': cqi.overall_score(),
                'cqi_breakdown': {
                    'accuracy': cqi.accuracy,
                    'efficiency': cqi.efficiency,
                    'personalization': cqi.personalization,
                    'proactiveness': cqi.proactiveness,
                    'consistency': cqi.consistency,
                    'learning': cqi.learning
                }
            })

        return results


# Convenience functions

def should_store_knowledge(
    content: str,
    context: Optional[Dict[str, Any]] = None
) -> bool:
    """
    Simple yes/no answer: should this knowledge be stored?

    Args:
        content: Knowledge content
        context: Optional context

    Returns:
        bool: True if should store, False otherwise
    """
    filter_instance = WorthinessFilter()
    decision, _, _ = filter_instance.is_worth_storing(content, context)
    return decision in (WorthinessDecision.STORE, WorthinessDecision.CONDITIONAL)


def get_worthiness_score(
    content: str,
    context: Optional[Dict[str, Any]] = None
) -> float:
    """
    Get numerical worthiness score (0.0-1.0).

    Args:
        content: Knowledge content
        context: Optional context

    Returns:
        float: Worthiness score (higher = more worth storing)
    """
    filter_instance = WorthinessFilter()
    boundary_classification = classify_knowledge_boundaries(content)
    cqi = filter_instance._evaluate_conversation_quality_improvement(
        content,
        boundary_classification,
        context or {}
    )
    return cqi.overall_score()


def explain_worthiness(
    content: str,
    context: Optional[Dict[str, Any]] = None
) -> str:
    """
    Get detailed explanation of worthiness judgment.

    Args:
        content: Knowledge content
        context: Optional context

    Returns:
        str: Multi-line explanation
    """
    filter_instance = WorthinessFilter()
    return filter_instance.explain_decision(content, context)
