"""
Confidence scoring system for Trax platform.

Provides detailed confidence analysis for transcript segments,
including individual segment scoring and overall confidence assessment.
"""

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

import numpy as np

from ..base.services import BaseService

logger = logging.getLogger(__name__)


class ConfidenceLevel(Enum):
    """Confidence level classifications."""
    VERY_LOW = "very_low"
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    VERY_HIGH = "very_high"


@dataclass
class SegmentConfidence:
    """Confidence analysis for a single segment."""
    segment_index: int
    text: str
    confidence_score: float
    confidence_level: ConfidenceLevel
    issues: List[str]
    suggestions: List[str]
    start_time: float
    end_time: float
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "segment_index": self.segment_index,
            "text": self.text,
            "confidence_score": self.confidence_score,
            "confidence_level": self.confidence_level.value,
            "issues": self.issues,
            "suggestions": self.suggestions,
            "start_time": self.start_time,
            "end_time": self.end_time
        }


class ConfidenceScorerProtocol(Protocol):
    """Protocol for confidence scoring services."""
    def calculate_segment_confidence(self, segment: Dict[str, Any]) -> float: ...
    def calculate_overall_confidence(self, segments: List[Dict[str, Any]]) -> float: ...
    def identify_low_confidence_segments(self, segments: List[Dict[str, Any]], threshold: float) -> List[Dict[str, Any]]: ...


class ConfidenceScorer(BaseService):
    """Score confidence for transcript segments."""
    
    def __init__(self):
        super().__init__("ConfidenceScorer")
        
        # Confidence thresholds
        self.base_confidence = 0.85
        self.min_confidence = 0.5
        self.max_confidence = 0.99
        
        # Confidence level thresholds
        self.confidence_thresholds = {
            ConfidenceLevel.VERY_LOW: 0.6,
            ConfidenceLevel.LOW: 0.7,
            ConfidenceLevel.MEDIUM: 0.8,
            ConfidenceLevel.HIGH: 0.9,
            ConfidenceLevel.VERY_HIGH: 0.95
        }
        
        # Text quality indicators
        self.quality_indicators = {
            "positive": [
                r'\b[A-Z][a-zA-Z0-9]*[A-Z][a-zA-Z0-9]*\b',  # CamelCase
                r'\b[a-z]+_[a-z]+(_[a-z]+)*\b',  # snake_case
                r'\b[A-Za-z]+\.[A-Za-z]+\b',  # dot.notation
                r'\b[A-Za-z0-9]+\([^)]*\)\b',  # function()
                r'\b[A-Z]{2,}\b',  # Acronyms
                r'\b\d+\.\d+\.\d+\b',  # Version numbers
            ],
            "negative": [
                r'\b(um|uh|er|ah|like|you know|i mean)\b',
                r'\b(sort of|kind of)\b',
                r'\.\.\.',
                r'\(inaudible\)',
                r'\(unintelligible\)',
                r'\b(\w+)\s+\1\b',  # Repeated words
            ]
        }
        
        logger.info("ConfidenceScorer initialized")
    
    def calculate_segment_confidence(self, segment: Dict[str, Any]) -> float:
        """Calculate confidence score for a single segment."""
        text = segment.get("text", "")
        base_confidence = segment.get("confidence", self.base_confidence)
        
        if not text.strip():
            return self.min_confidence
        
        # Analyze text quality
        quality_score = self._analyze_text_quality(text)
        
        # Calculate segment length factor
        word_count = len(text.split())
        length_factor = self._calculate_length_factor(word_count)
        
        # Calculate final confidence
        confidence = base_confidence * quality_score * length_factor
        
        return max(self.min_confidence, min(self.max_confidence, confidence))
    
    def calculate_overall_confidence(self, segments: List[Dict[str, Any]]) -> float:
        """Calculate overall confidence for all segments."""
        if not segments:
            return self.min_confidence
        
        # Calculate individual segment confidences
        segment_confidences = []
        segment_weights = []
        
        for segment in segments:
            confidence = self.calculate_segment_confidence(segment)
            segment_confidences.append(confidence)
            
            # Weight by segment length (longer segments have more impact)
            word_count = len(segment.get("text", "").split())
            segment_weights.append(max(1, word_count))
        
        # Calculate weighted average
        total_weight = sum(segment_weights)
        if total_weight == 0:
            return self.min_confidence
        
        weighted_confidence = sum(
            conf * weight for conf, weight in zip(segment_confidences, segment_weights)
        ) / total_weight
        
        return weighted_confidence
    
    def identify_low_confidence_segments(
        self, 
        segments: List[Dict[str, Any]], 
        threshold: float = 0.7
    ) -> List[Dict[str, Any]]:
        """Identify segments with confidence below threshold."""
        low_confidence_segments = []
        
        for i, segment in enumerate(segments):
            confidence = self.calculate_segment_confidence(segment)
            if confidence < threshold:
                segment_copy = segment.copy()
                segment_copy["segment_index"] = i
                segment_copy["calculated_confidence"] = confidence
                low_confidence_segments.append(segment_copy)
        
        return low_confidence_segments
    
    def analyze_segment_confidence(self, segment: Dict[str, Any], segment_index: int) -> SegmentConfidence:
        """Detailed confidence analysis for a segment."""
        text = segment.get("text", "")
        confidence_score = self.calculate_segment_confidence(segment)
        confidence_level = self._get_confidence_level(confidence_score)
        
        # Analyze issues
        issues = self._identify_segment_issues(text, confidence_score)
        
        # Generate suggestions
        suggestions = self._generate_suggestions(text, confidence_score, issues)
        
        return SegmentConfidence(
            segment_index=segment_index,
            text=text,
            confidence_score=confidence_score,
            confidence_level=confidence_level,
            issues=issues,
            suggestions=suggestions,
            start_time=segment.get("start", 0.0),
            end_time=segment.get("end", 0.0)
        )
    
    def get_confidence_distribution(self, segments: List[Dict[str, Any]]) -> Dict[str, Any]:
        """Get distribution of confidence levels across segments."""
        if not segments:
            return {"error": "No segments provided"}
        
        confidence_scores = []
        level_counts = {level.value: 0 for level in ConfidenceLevel}
        
        for segment in segments:
            confidence = self.calculate_segment_confidence(segment)
            confidence_scores.append(confidence)
            level = self._get_confidence_level(confidence)
            level_counts[level.value] += 1
        
        return {
            "total_segments": len(segments),
            "average_confidence": np.mean(confidence_scores),
            "min_confidence": np.min(confidence_scores),
            "max_confidence": np.max(confidence_scores),
            "confidence_std": np.std(confidence_scores),
            "level_distribution": level_counts,
            "low_confidence_percentage": (level_counts["very_low"] + level_counts["low"]) / len(segments) * 100
        }
    
    def _analyze_text_quality(self, text: str) -> float:
        """Analyze text quality and return quality score."""
        if not text.strip():
            return 0.5
        
        # Count positive and negative indicators
        positive_count = 0
        negative_count = 0
        
        for pattern in self.quality_indicators["positive"]:
            positive_count += len(re.findall(pattern, text))
        
        for pattern in self.quality_indicators["negative"]:
            negative_count += len(re.findall(pattern, text, re.IGNORECASE))
        
        # Calculate quality score
        word_count = len(text.split())
        if word_count == 0:
            return 0.5
        
        positive_ratio = positive_count / word_count
        negative_ratio = negative_count / word_count
        
        # Quality score: positive indicators boost, negative indicators reduce
        quality_score = 1.0 + (positive_ratio * 0.1) - (negative_ratio * 0.2)
        
        return max(0.5, min(1.2, quality_score))
    
    def _calculate_length_factor(self, word_count: int) -> float:
        """Calculate confidence factor based on segment length."""
        if word_count < 3:
            return 0.8  # Very short segments are less reliable
        elif word_count < 10:
            return 0.9  # Short segments
        elif word_count < 50:
            return 1.0  # Normal length
        else:
            return 0.95  # Very long segments may have more errors
    
    def _get_confidence_level(self, confidence_score: float) -> ConfidenceLevel:
        """Get confidence level based on score."""
        if confidence_score >= self.confidence_thresholds[ConfidenceLevel.VERY_HIGH]:
            return ConfidenceLevel.VERY_HIGH
        elif confidence_score >= self.confidence_thresholds[ConfidenceLevel.HIGH]:
            return ConfidenceLevel.HIGH
        elif confidence_score >= self.confidence_thresholds[ConfidenceLevel.MEDIUM]:
            return ConfidenceLevel.MEDIUM
        elif confidence_score >= self.confidence_thresholds[ConfidenceLevel.LOW]:
            return ConfidenceLevel.LOW
        else:
            return ConfidenceLevel.VERY_LOW
    
    def _identify_segment_issues(self, text: str, confidence_score: float) -> List[str]:
        """Identify specific issues in a segment."""
        issues = []
        
        if confidence_score < 0.7:
            issues.append("Low confidence score")
        
        # Check for filler words
        filler_words = re.findall(r'\b(um|uh|er|ah|like|you know|i mean)\b', text, re.IGNORECASE)
        if len(filler_words) > 2:
            issues.append(f"Multiple filler words detected: {len(filler_words)}")
        
        # Check for repeated words
        if re.search(r'\b(\w+)\s+\1\b', text, re.IGNORECASE):
            issues.append("Repeated words detected")
        
        # Check for inaudible markers
        if re.search(r'\(inaudible\)|\(unintelligible\)', text, re.IGNORECASE):
            issues.append("Inaudible sections detected")
        
        # Check for very short segments
        if len(text.split()) < 3:
            issues.append("Very short segment")
        
        # Check for excessive punctuation
        if text.count('.') + text.count('!') + text.count('?') > len(text.split()) * 0.3:
            issues.append("Excessive punctuation")
        
        return issues
    
    def _generate_suggestions(self, text: str, confidence_score: float, issues: List[str]) -> List[str]:
        """Generate improvement suggestions for a segment."""
        suggestions = []
        
        if confidence_score < 0.7:
            suggestions.append("Consider manual review of this segment")
        
        if "Multiple filler words detected" in issues:
            suggestions.append("Consider editing out filler words")
        
        if "Repeated words detected" in issues:
            suggestions.append("Check for stuttering or transcription errors")
        
        if "Inaudible sections detected" in issues:
            suggestions.append("Audio quality may need improvement")
        
        if "Very short segment" in issues:
            suggestions.append("Segment may be incomplete")
        
        if not suggestions:
            suggestions.append("Segment appears to be of good quality")
        
        return suggestions
    
    async def _initialize_impl(self) -> None:
        """Initialize the confidence scorer."""
        logger.info("ConfidenceScorer initialized")


def create_confidence_scorer() -> ConfidenceScorer:
    """Create a confidence scorer instance."""
    return ConfidenceScorer()
