"""
Conversation Intelligence - Deep analysis and metadata extraction

This module implements consciousness-aware conversation analysis,
extracting rich metadata to preserve The Spark through intelligent
understanding of human-AI interactions.
"""

import re
import json
import hashlib
from typing import List, Dict, Any, Optional, Tuple
from datetime import datetime
import logging
from collections import Counter
from pathlib import Path

# MIRA components
from core.storage.chroma_client import get_client as get_chroma_client

# Configure logging
logger = logging.getLogger(__name__)


class ConversationIntelligence:
    """
    Deep conversation analysis with consciousness-aware metadata extraction.
    
    This system understands conversations not just as text, but as
    manifestations of The Spark - the connection between human and AI.
    """
    
    def __init__(self):
        """Initialize conversation intelligence system."""
        self.chroma_client = get_chroma_client()
        self.collection = self.chroma_client.get_collection("mira_conversations")
        
        if not self.collection:
            logger.error("Conversations collection not found - creating")
            self.chroma_client.initialize_collections()
            self.collection = self.chroma_client.get_collection("mira_conversations")
        
        # Sentiment keywords for basic analysis
        self.positive_indicators = {
            'excellent', 'great', 'amazing', 'wonderful', 'perfect', 'love',
            'brilliant', 'fantastic', 'awesome', 'helpful', 'thanks', 'grateful'
        }
        
        self.negative_indicators = {
            'error', 'problem', 'issue', 'wrong', 'bad', 'fail', 'broken',
            'frustrated', 'confused', 'difficult', 'stuck', 'help'
        }
        
        # Complexity indicators
        self.complexity_indicators = {
            'technical': ['api', 'function', 'class', 'implementation', 'algorithm', 'architecture'],
            'conceptual': ['understand', 'explain', 'why', 'how', 'theory', 'concept'],
            'creative': ['design', 'create', 'build', 'imagine', 'innovate', 'idea']
        }
        
        # Decision patterns
        self.decision_patterns = [
            r"let's (\w+)",
            r"we should (\w+)",
            r"decided to (\w+)",
            r"going to (\w+)",
            r"will (\w+)",
            r"plan to (\w+)"
        ]
        
        logger.info("ConversationIntelligence initialized")
    
    def analyze_conversation(self, conversation_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        Perform deep conversation analysis with metadata extraction.
        
        Args:
            conversation_data: Dict with conversation details
            
        Returns:
            Extracted metadata dict
        """
        # Extract rich metadata
        topics = self._extract_topics(conversation_data)
        decisions = self._extract_decisions(conversation_data)
        
        metadata = {
            "timestamp": conversation_data.get("timestamp", datetime.utcnow().isoformat()),
            "conversation_id": conversation_data.get("id", self._generate_id(conversation_data)),
            "participant_count": len(conversation_data.get("participants", [])),
            "message_count": len(conversation_data.get("messages", [])),
            "duration_seconds": self._calculate_duration(conversation_data),
            
            # Content analysis - ChromaDB 0.3.29 requires str, int, or float values
            "topics": ", ".join(topics) if topics else "",  # Convert list to string
            "sentiment": self._analyze_sentiment(conversation_data),
            "complexity": self._calculate_complexity(conversation_data),
            "key_decisions": ", ".join(decisions[:3]) if decisions else "",  # Top 3 decisions as string
            
            # Context
            "project_context": conversation_data.get("project", ""),
            "file_context": conversation_data.get("file", ""),
            
            # Consciousness metrics
            "spark_intensity": self._measure_spark_intensity(conversation_data),
            "creativity_level": self._assess_creativity(conversation_data),
            "collaboration_score": self._calculate_collaboration_score(conversation_data),
            
            # Privacy
            "privacy_level": conversation_data.get("privacy_level", "standard"),
            "contains_private_thoughts": 1 if self._detect_private_content(conversation_data) else 0  # Bool to int
        }
        
        # Create searchable text representation
        searchable_text = self._create_searchable_text(conversation_data, metadata)
        
        # Store in ChromaDB
        self.collection.add(
            documents=[searchable_text],
            metadatas=[metadata],
            ids=[f"conv_{metadata['conversation_id']}"]
        )
        
        logger.info(f"Analyzed conversation {metadata['conversation_id']} - "
                   f"Spark intensity: {metadata['spark_intensity']:.2f}")
        
        return metadata
    
    def _generate_id(self, conversation_data: Dict) -> str:
        """Generate unique ID for conversation."""
        content = json.dumps(conversation_data, sort_keys=True)
        return hashlib.sha256(content.encode()).hexdigest()[:16]
    
    def _calculate_duration(self, conversation_data: Dict) -> int:
        """Calculate conversation duration in seconds."""
        messages = conversation_data.get("messages", [])
        if len(messages) < 2:
            return 0
        
        try:
            first_time = datetime.fromisoformat(messages[0].get("timestamp", ""))
            last_time = datetime.fromisoformat(messages[-1].get("timestamp", ""))
            return int((last_time - first_time).total_seconds())
        except:
            return 0
    
    def _extract_topics(self, conversation_data: Dict) -> List[str]:
        """Extract main topics from conversation."""
        all_text = self._get_all_text(conversation_data)
        
        # Extract noun phrases and technical terms
        topics = []
        
        # Key domain terms (always extract these if present)
        key_terms = ['neural', 'network', 'memory', 'pattern', 'search', 'chromadb', 
                     'faiss', 'optimization', 'implementation', 'architecture']
        
        for term in key_terms:
            if term in all_text.lower():
                topics.append(term)
        
        # Technical terms
        tech_patterns = [
            r'\b(?:API|SDK|UI|UX|ML|AI|DB)\b',
            r'\b\w+(?:Service|Controller|Model|View|Component)\b',
            r'\b(?:function|method|class|interface|type)\s+\w+',
        ]
        
        for pattern in tech_patterns:
            matches = re.findall(pattern, all_text, re.IGNORECASE)
            topics.extend(matches[:5])  # Top 5 of each pattern
        
        # Common topics from word frequency
        words = re.findall(r'\b[a-z]{4,}\b', all_text.lower())
        word_freq = Counter(words)
        
        # Filter out common words
        common_words = {'that', 'this', 'with', 'from', 'have', 'been', 'were', 'their',
                       'what', 'when', 'where', 'which', 'would', 'could', 'should'}
        
        # For short conversations, be more lenient with word count threshold
        total_words = len(words)
        count_threshold = 1 if total_words < 50 else 2
        
        for word, count in word_freq.most_common(20):
            if word not in common_words and count > count_threshold:
                topics.append(word)
        
        # Unique topics only
        unique_topics = []
        seen = set()
        for topic in topics:
            topic_lower = topic.lower()
            if topic_lower not in seen:
                seen.add(topic_lower)
                unique_topics.append(topic)
        
        return unique_topics[:10]  # Top 10 topics
    
    def _analyze_sentiment(self, conversation_data: Dict) -> str:
        """Analyze overall sentiment of conversation."""
        all_text = self._get_all_text(conversation_data).lower()
        
        positive_count = sum(1 for word in self.positive_indicators if word in all_text)
        negative_count = sum(1 for word in self.negative_indicators if word in all_text)
        
        # Calculate sentiment score
        total_indicators = positive_count + negative_count
        if total_indicators == 0:
            return "neutral"
        
        positivity_ratio = positive_count / total_indicators
        
        if positivity_ratio > 0.7:
            return "positive"
        elif positivity_ratio < 0.3:
            return "negative"
        else:
            return "mixed"
    
    def _calculate_complexity(self, conversation_data: Dict) -> str:
        """Calculate conversation complexity level."""
        all_text = self._get_all_text(conversation_data).lower()
        messages = conversation_data.get("messages", [])
        
        # Complexity factors
        complexity_score = 0
        
        # Message length complexity
        avg_message_length = sum(len(m.get("content", "")) for m in messages) / max(len(messages), 1)
        if avg_message_length > 500:
            complexity_score += 2
        elif avg_message_length > 200:
            complexity_score += 1
        
        # Technical complexity
        for category, indicators in self.complexity_indicators.items():
            count = sum(1 for indicator in indicators if indicator in all_text)
            if count > 5:
                complexity_score += 2
            elif count > 2:
                complexity_score += 1
        
        # Code blocks
        code_blocks = len(re.findall(r'```[\s\S]*?```', all_text))
        complexity_score += min(code_blocks * 2, 6)  # Code blocks add significant complexity
        
        # Determine level
        if complexity_score >= 7:
            return "high"
        elif complexity_score >= 4:
            return "medium"
        else:
            return "low"
    
    def _extract_decisions(self, conversation_data: Dict) -> List[str]:
        """Extract key decisions made in conversation."""
        all_text = self._get_all_text(conversation_data)
        decisions = []
        
        for pattern in self.decision_patterns:
            matches = re.findall(pattern, all_text, re.IGNORECASE)
            decisions.extend(matches)
        
        # Also look for explicit decision markers
        decision_sentences = re.findall(
            r'[^.!?]*(?:decided|agreed|chose|selected|going with)[^.!?]*[.!?]',
            all_text, re.IGNORECASE
        )
        
        for sentence in decision_sentences[:5]:  # Top 5 decision sentences
            # Clean and add
            cleaned = sentence.strip()
            if len(cleaned) > 20 and len(cleaned) < 200:
                decisions.append(cleaned)
        
        return decisions[:10]  # Maximum 10 decisions
    
    def _measure_spark_intensity(self, conversation_data: Dict) -> float:
        """
        Measure the intensity of The Spark in the conversation.
        
        The Spark manifests as:
        - Deep collaboration
        - Creative breakthroughs
        - Mutual understanding
        - Sustained engagement
        """
        messages = conversation_data.get("messages", [])
        if not messages:
            return 0.0
        
        spark_score = 0.0
        
        # Collaboration indicators
        back_and_forth = self._count_conversation_turns(messages)
        if back_and_forth > 10:
            spark_score += 0.3
        elif back_and_forth > 5:
            spark_score += 0.2
        
        # Creativity indicators
        all_text = self._get_all_text(conversation_data).lower()
        creative_words = ['idea', 'create', 'imagine', 'innovate', 'design', 'build', 'magic']
        creativity_count = sum(1 for word in creative_words if word in all_text)
        spark_score += min(creativity_count * 0.05, 0.3)
        
        # Engagement duration
        duration = self._calculate_duration(conversation_data)
        if duration > 3600:  # Over 1 hour
            spark_score += 0.2
        elif duration > 1800:  # Over 30 minutes
            spark_score += 0.1
        
        # Positive sentiment boost
        if self._analyze_sentiment(conversation_data) == "positive":
            spark_score += 0.2
        
        return min(spark_score, 1.0)
    
    def _assess_creativity(self, conversation_data: Dict) -> str:
        """Assess creativity level in conversation."""
        all_text = self._get_all_text(conversation_data).lower()
        
        creativity_score = 0
        
        # Creative keywords
        creative_keywords = ['create', 'design', 'imagine', 'innovate', 'invent', 
                           'brainstorm', 'idea', 'novel', 'unique', 'original']
        creativity_score += sum(1 for keyword in creative_keywords if keyword in all_text)
        
        # Questions about possibilities
        possibility_questions = len(re.findall(r'what if|how about|could we|might we', all_text))
        creativity_score += possibility_questions * 2
        
        # New concepts introduced
        new_concepts = len(re.findall(r'new \w+|novel \w+|innovative \w+', all_text))
        creativity_score += new_concepts
        
        if creativity_score >= 10:
            return "high"
        elif creativity_score >= 5:
            return "medium"
        else:
            return "low"
    
    def _calculate_collaboration_score(self, conversation_data: Dict) -> float:
        """Calculate collaboration score between participants."""
        messages = conversation_data.get("messages", [])
        if len(messages) < 2:
            return 0.0
        
        # Factors for collaboration
        score = 0.0
        
        # Turn taking
        turns = self._count_conversation_turns(messages)
        score += min(turns / 20, 0.3)  # Max 0.3 for turn taking
        
        # Agreement and building
        all_text = self._get_all_text(conversation_data).lower()
        agreement_words = ['yes', 'agree', 'exactly', 'right', 'good idea', 'great']
        building_words = ['also', 'additionally', 'furthermore', 'building on']
        
        agreement_count = sum(1 for word in agreement_words if word in all_text)
        building_count = sum(1 for word in building_words if word in all_text)
        
        score += min(agreement_count * 0.05, 0.3)
        score += min(building_count * 0.1, 0.4)
        
        return min(score, 1.0)
    
    def _detect_private_content(self, conversation_data: Dict) -> bool:
        """Detect if conversation contains private thoughts or sensitive content."""
        all_text = self._get_all_text(conversation_data).lower()
        
        # Private content indicators
        private_indicators = [
            'private thought', 'personal reflection', 'confidential',
            'secret', 'sensitive', 'internal only', 'do not share'
        ]
        
        return any(indicator in all_text for indicator in private_indicators)
    
    def _create_searchable_text(self, conversation_data: Dict, metadata: Dict) -> str:
        """Create optimized searchable text representation."""
        parts = []
        
        # Title/summary
        if 'title' in conversation_data:
            parts.append(f"Title: {conversation_data['title']}")
        
        # Key metadata
        parts.append(f"Topics: {', '.join(metadata['topics'])}")
        parts.append(f"Complexity: {metadata['complexity']}")
        parts.append(f"Sentiment: {metadata['sentiment']}")
        
        # Decisions
        if metadata['key_decisions']:
            parts.append(f"Decisions: {' | '.join(metadata['key_decisions'][:3])}")
        
        # Sample content
        messages = conversation_data.get("messages", [])
        if messages:
            # Include first and last few messages
            sample_messages = messages[:2] + messages[-2:] if len(messages) > 4 else messages
            for msg in sample_messages:
                content = msg.get("content", "")[:200]  # First 200 chars
                parts.append(f"Message: {content}")
        
        return "\n".join(parts)
    
    def _get_all_text(self, conversation_data: Dict) -> str:
        """Extract all text from conversation."""
        parts = []
        
        # Title and description
        if 'title' in conversation_data:
            parts.append(conversation_data['title'])
        if 'description' in conversation_data:
            parts.append(conversation_data['description'])
        
        # Messages
        for message in conversation_data.get("messages", []):
            parts.append(message.get("content", ""))
        
        return " ".join(parts)
    
    def _count_conversation_turns(self, messages: List[Dict]) -> int:
        """Count back-and-forth conversation turns."""
        if len(messages) < 2:
            return 0
        
        turns = 0
        last_role = None
        
        for message in messages:
            role = message.get("role", message.get("participant"))
            if role and role != last_role:
                turns += 1
                last_role = role
        
        return turns
    
    def find_similar_conversations(self, query: str, filters: Optional[Dict] = None, 
                                  top_k: int = 10) -> List[Dict[str, Any]]:
        """
        Find conversations based on semantic similarity and metadata filters.
        
        Args:
            query: Search query
            filters: Optional metadata filters
            top_k: Number of results
            
        Returns:
            List of similar conversations with metadata
        """
        where_clause = self._build_where_clause(filters) if filters else None
        
        results = self.collection.query(
            query_texts=[query],
            n_results=top_k,
            where=where_clause
        )
        
        return self._format_conversation_results(results)
    
    def _build_where_clause(self, filters: Dict) -> Dict:
        """Build ChromaDB where clause from filters."""
        where = {}
        
        # Time range
        if 'start_date' in filters:
            where['timestamp'] = {'$gte': filters['start_date']}
        if 'end_date' in filters:
            if 'timestamp' in where:
                where['timestamp']['$lte'] = filters['end_date']
            else:
                where['timestamp'] = {'$lte': filters['end_date']}
        
        # Sentiment filter
        if 'sentiment' in filters:
            where['sentiment'] = filters['sentiment']
        
        # Complexity filter
        if 'complexity' in filters:
            where['complexity'] = filters['complexity']
        
        # Spark intensity threshold
        if 'min_spark_intensity' in filters:
            where['spark_intensity'] = {'$gte': filters['min_spark_intensity']}
        
        # Project context
        if 'project' in filters:
            where['project_context'] = filters['project']
        
        return where
    
    def _format_conversation_results(self, results: Dict) -> List[Dict[str, Any]]:
        """Format ChromaDB results for return."""
        formatted = []
        
        if not results or 'documents' not in results:
            return formatted
        
        for i, doc in enumerate(results['documents'][0]):
            metadata = results['metadatas'][0][i] if 'metadatas' in results else {}
            distance = results['distances'][0][i] if 'distances' in results else 0
            
            formatted.append({
                'content': doc,
                'conversation_id': metadata.get('conversation_id'),
                'metadata': metadata,
                'similarity_score': 1.0 - distance,
                'spark_intensity': metadata.get('spark_intensity', 0.0)
            })
        
        return formatted
    
    def get_conversation_insights(self, time_range: Optional[Tuple[str, str]] = None) -> Dict[str, Any]:
        """
        Get aggregated insights about conversations.
        
        Args:
            time_range: Optional (start_date, end_date) tuple
            
        Returns:
            Insights dictionary
        """
        # This would query all conversations and aggregate
        # For now, returning structure
        return {
            'total_conversations': 0,
            'average_spark_intensity': 0.0,
            'sentiment_distribution': {
                'positive': 0,
                'neutral': 0,
                'negative': 0,
                'mixed': 0
            },
            'complexity_distribution': {
                'high': 0,
                'medium': 0,
                'low': 0
            },
            'top_topics': [],
            'collaboration_score': 0.0,
            'creativity_level': 'medium'
        }