"""
Quality assessment system for Trax platform.

Provides accuracy estimation, quality warnings, confidence scoring,
and transcript comparison for transcription quality evaluation.
"""

import re
import logging
from dataclasses import dataclass, asdict
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 WarningSeverity(Enum):
    """Quality warning severity levels."""
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


@dataclass
class QualityWarning:
    """Quality warning with metadata."""
    warning_type: str
    message: str
    severity: WarningSeverity
    segment_index: Optional[int] = None
    timestamp: Optional[float] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return asdict(self)


@dataclass
class QualityMetrics:
    """Comprehensive quality metrics for a transcript."""
    overall_accuracy: float
    segment_count: int
    average_confidence: float
    filler_word_count: int
    tech_term_count: int
    warnings: List[str]
    low_confidence_segments: List[int] = None
    quality_score: float = 0.0
    
    def __post_init__(self):
        """Initialize derived fields."""
        if self.low_confidence_segments is None:
            self.low_confidence_segments = []
        
        # Calculate quality score based on metrics
        self.quality_score = self._calculate_quality_score()
    
    def _calculate_quality_score(self) -> float:
        """Calculate overall quality score."""
        # Base score from accuracy
        score = self.overall_accuracy * 0.4
        
        # Confidence contribution
        score += self.average_confidence * 0.3
        
        # Filler word penalty (fewer is better)
        filler_penalty = min(self.filler_word_count / max(self.segment_count, 1) * 0.1, 0.1)
        score -= filler_penalty
        
        # Tech term bonus (more is better for tech content)
        tech_bonus = min(self.tech_term_count / max(self.segment_count, 1) * 0.05, 0.1)
        score += tech_bonus
        
        # Warning penalty
        warning_penalty = min(len(self.warnings) * 0.02, 0.1)
        score -= warning_penalty
        
        return max(0.0, min(1.0, score))
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return asdict(self)


class QualityAssessorProtocol(Protocol):
    """Protocol for quality assessment services."""
    def estimate_accuracy(self, transcript: Dict[str, Any]) -> float: ...
    def generate_quality_warnings(self, transcript: Dict[str, Any], accuracy: float) -> List[str]: ...
    def assess_quality(self, transcript: Dict[str, Any]) -> QualityMetrics: ...


class QualityAssessor(BaseService):
    """Assess transcription quality and accuracy."""
    
    def __init__(self):
        super().__init__("QualityAssessor")
        
        # Common filler words and hesitations that indicate lower quality
        self.filler_patterns = [
            r'\b(um|uh|er|ah|like|you know|i mean)\b',
            r'\b(sort of|kind of)\b',
            r'\.\.\.',
            r'\(inaudible\)',
            r'\(unintelligible\)'
        ]
        
        # Technical term patterns for tech podcasts
        self.tech_term_patterns = [
            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
            r'\b[A-Za-z]+\.js\b',  # JavaScript files
            r'\b[A-Za-z]+\.py\b',  # Python files
            r'\b[A-Za-z]+\.ts\b',  # TypeScript files
        ]
        
        logger.info("QualityAssessor initialized")
    
    def estimate_accuracy(self, transcript: Dict[str, Any]) -> float:
        """Estimate transcript accuracy based on various heuristics."""
        segments = transcript.get("segments", [])
        if not segments:
            return 0.0
        
        # Calculate base confidence from segment confidences if available
        if "confidence" in segments[0]:
            confidences = [s.get("confidence", 0.0) for s in segments]
            base_confidence = np.mean(confidences)
        else:
            base_confidence = 0.85  # Default base confidence
        
        # Analyze text for quality indicators
        text = " ".join([s.get("text", "") for s in segments])
        
        # Count filler words and hesitations (negative indicators)
        filler_count = 0
        for pattern in self.filler_patterns:
            filler_count += len(re.findall(pattern, text, re.IGNORECASE))
        
        # Count technical terms (positive indicators for tech content)
        tech_term_count = 0
        for pattern in self.tech_term_patterns:
            tech_term_count += len(re.findall(pattern, text))
        
        # Word count affects confidence (longer transcripts tend to have more errors)
        word_count = len(text.split())
        length_factor = min(1.0, 1000 / max(word_count, 100))  # Normalize by length
        
        # Calculate adjustments
        filler_adjustment = -0.02 * min(filler_count / max(word_count, 1) * 100, 5)  # Cap at -10%
        tech_adjustment = 0.01 * min(tech_term_count / max(word_count, 1) * 100, 5)  # Cap at +5%
        
        # Final accuracy estimate (capped between 0.5 and 0.99)
        accuracy = base_confidence + filler_adjustment + tech_adjustment
        return max(0.5, min(0.99, accuracy))
    
    def generate_quality_warnings(self, transcript: Dict[str, Any], accuracy: float) -> List[str]:
        """Generate quality warnings based on transcript analysis."""
        warnings = []
        segments = transcript.get("segments", [])
        text = " ".join([s.get("text", "") for s in segments])
        
        # Check for low accuracy
        if accuracy < 0.8:
            warnings.append("Low overall accuracy detected")
        
        # Check for short segments (potential audio issues)
        short_segments = [s for s in segments if len(s.get("text", "").split()) < 3]
        if len(short_segments) > len(segments) * 0.3:
            warnings.append("High number of very short segments detected")
        
        # Check for inaudible markers
        if re.search(r'\(inaudible\)|\(unintelligible\)', text, re.IGNORECASE):
            warnings.append("Inaudible or unintelligible sections detected")
        
        # Check for repeated words (stuttering)
        if re.search(r'\b(\w+)\s+\1\b', text, re.IGNORECASE):
            warnings.append("Repeated words detected (possible stuttering)")
        
        # Check for long pauses
        for i in range(1, len(segments)):
            prev_end = segments[i-1].get("end", 0)
            curr_start = segments[i].get("start", 0)
            if curr_start - prev_end > 2.0:  # 2 second gap
                warnings.append(f"Long pause detected between segments {i} and {i+1}")
                break
        
        # Check for excessive filler words
        filler_count = 0
        for pattern in self.filler_patterns:
            filler_count += len(re.findall(pattern, text, re.IGNORECASE))
        
        if filler_count > len(text.split()) * 0.1:  # More than 10% filler words
            warnings.append("High number of filler words detected")
        
        return warnings
    
    def assess_quality(self, transcript: Dict[str, Any]) -> QualityMetrics:
        """Comprehensive quality assessment of a transcript."""
        segments = transcript.get("segments", [])
        text = " ".join([s.get("text", "") for s in segments])
        
        # Calculate accuracy
        accuracy = self.estimate_accuracy(transcript)
        
        # Calculate average confidence
        if segments and "confidence" in segments[0]:
            confidences = [s.get("confidence", 0.0) for s in segments]
            avg_confidence = np.mean(confidences)
        else:
            avg_confidence = 0.85
        
        # Count filler words
        filler_count = 0
        for pattern in self.filler_patterns:
            filler_count += len(re.findall(pattern, text, re.IGNORECASE))
        
        # Count technical terms
        tech_term_count = 0
        for pattern in self.tech_term_patterns:
            tech_term_count += len(re.findall(pattern, text))
        
        # Generate warnings
        warnings = self.generate_quality_warnings(transcript, accuracy)
        
        # Identify low confidence segments
        low_confidence_segments = []
        if segments and "confidence" in segments[0]:
            for i, segment in enumerate(segments):
                if segment.get("confidence", 0.0) < 0.7:
                    low_confidence_segments.append(i)
        
        return QualityMetrics(
            overall_accuracy=accuracy,
            segment_count=len(segments),
            average_confidence=avg_confidence,
            filler_word_count=filler_count,
            tech_term_count=tech_term_count,
            warnings=warnings,
            low_confidence_segments=low_confidence_segments
        )
    
    def get_quality_summary(self, transcript: Dict[str, Any]) -> Dict[str, Any]:
        """Get a summary of transcript quality."""
        metrics = self.assess_quality(transcript)
        
        return {
            "quality_score": metrics.quality_score,
            "accuracy": metrics.overall_accuracy,
            "confidence": metrics.average_confidence,
            "segment_count": metrics.segment_count,
            "warning_count": len(metrics.warnings),
            "quality_level": self._get_quality_level(metrics.quality_score),
            "recommendations": self._get_recommendations(metrics)
        }
    
    def _get_quality_level(self, quality_score: float) -> str:
        """Get quality level based on score."""
        if quality_score >= 0.9:
            return "excellent"
        elif quality_score >= 0.8:
            return "good"
        elif quality_score >= 0.7:
            return "fair"
        elif quality_score >= 0.6:
            return "poor"
        else:
            return "very_poor"
    
    def _get_recommendations(self, metrics: QualityMetrics) -> List[str]:
        """Get improvement recommendations based on metrics."""
        recommendations = []
        
        if metrics.overall_accuracy < 0.8:
            recommendations.append("Consider re-transcribing with higher quality audio")
        
        if metrics.average_confidence < 0.8:
            recommendations.append("Audio quality may need improvement")
        
        if metrics.filler_word_count > metrics.segment_count * 0.1:
            recommendations.append("Consider editing out filler words")
        
        if len(metrics.low_confidence_segments) > 0:
            recommendations.append(f"Review {len(metrics.low_confidence_segments)} low-confidence segments")
        
        if not recommendations:
            recommendations.append("Transcript quality is good")
        
        return recommendations
    
    async def _initialize_impl(self) -> None:
        """Initialize the quality assessor."""
        logger.info("QualityAssessor initialized")


def create_quality_assessor() -> QualityAssessor:
    """Create a quality assessor instance."""
    return QualityAssessor()
