"""Dynamic threshold adjustment based on LLM feedback."""
import logging
from typing import Dict, List, Any
from collections import defaultdict
from dataclasses import dataclass, field

logger = logging.getLogger(__name__)


@dataclass
class ClassificationFeedback:
    """Feedback from LLM classification."""
    email_id: str
    ml_prediction: str
    ml_confidence: float
    llm_correction: str
    llm_confidence: float
    agreement: bool = field(init=False)

    def __post_init__(self):
        """Calculate agreement."""
        self.agreement = self.ml_prediction == self.llm_correction


class ThresholdAdjuster:
    """
    Dynamically adjust classification thresholds based on LLM feedback.

    Tracks:
    - Agreement rate between ML and LLM
    - False positive/negative rates per category
    - Optimal threshold for each category
    """

    def __init__(self, initial_thresholds: Dict[str, float]):
        """Initialize with baseline thresholds."""
        self.thresholds = initial_thresholds.copy()
        self.feedback_history: List[ClassificationFeedback] = []

        # Stats tracking
        self.category_stats = defaultdict(lambda: {
            'total': 0,
            'llm_corrections': 0,
            'ml_overconfident': 0,
            'ml_underconfident': 0,
            'agreement_rate': 1.0,
            'adjustment_history': []
        })

    def record_feedback(self, feedback: ClassificationFeedback) -> None:
        """Record LLM feedback on a classification."""
        self.feedback_history.append(feedback)

        # Update category stats
        category = feedback.ml_prediction
        stats = self.category_stats[category]
        stats['total'] += 1

        if not feedback.agreement:
            stats['llm_corrections'] += 1

            # Was ML overconfident (high confidence but wrong)?
            if feedback.ml_confidence > self.thresholds[category]:
                stats['ml_overconfident'] += 1

            # Was ML underconfident (low confidence but actually correct)?
            elif feedback.llm_confidence > self.thresholds[category]:
                stats['ml_underconfident'] += 1

    def analyze_feedback_batch(self, batch_feedback: List[ClassificationFeedback]) -> Dict[str, Any]:
        """Analyze batch of feedback and suggest adjustments."""
        for feedback in batch_feedback:
            self.record_feedback(feedback)

        suggestions = {}

        for category, stats in self.category_stats.items():
            if stats['total'] == 0:
                continue

            # Calculate agreement rate
            agreement_rate = 1.0 - (stats['llm_corrections'] / stats['total'])
            stats['agreement_rate'] = agreement_rate

            # Suggest adjustment if agreement is poor
            if agreement_rate < 0.85:  # Less than 85% agreement
                if stats['ml_overconfident'] > stats['ml_underconfident']:
                    # ML is too confident, raise threshold
                    adjustment = +0.05
                    new_threshold = min(
                        self.thresholds[category] + adjustment,
                        0.95
                    )
                    suggestions[category] = {
                        'action': 'raise_threshold',
                        'current': self.thresholds[category],
                        'suggested': new_threshold,
                        'reason': f'ML overconfident ({stats["ml_overconfident"]} cases)',
                        'agreement_rate': agreement_rate
                    }
                else:
                    # ML is too conservative, lower threshold
                    adjustment = -0.05
                    new_threshold = max(
                        self.thresholds[category] - adjustment,
                        0.50
                    )
                    suggestions[category] = {
                        'action': 'lower_threshold',
                        'current': self.thresholds[category],
                        'suggested': new_threshold,
                        'reason': f'ML underconfident ({stats["ml_underconfident"]} cases)',
                        'agreement_rate': agreement_rate
                    }

        return suggestions

    def apply_adjustments(self, suggestions: Dict[str, Dict[str, Any]]) -> bool:
        """Apply suggested threshold adjustments."""
        try:
            for category, suggestion in suggestions.items():
                if 'suggested' in suggestion:
                    old_threshold = self.thresholds[category]
                    new_threshold = suggestion['suggested']

                    self.thresholds[category] = new_threshold
                    self.category_stats[category]['adjustment_history'].append({
                        'from': old_threshold,
                        'to': new_threshold,
                        'reason': suggestion.get('reason', 'feedback-driven')
                    })

                    logger.info(
                        f"Adjusted {category} threshold: {old_threshold:.3f} → {new_threshold:.3f} "
                        f"({suggestion.get('reason', 'feedback')})"
                    )

            return True
        except Exception as e:
            logger.error(f"Error applying adjustments: {e}")
            return False

    def get_stats(self) -> Dict[str, Any]:
        """Get adjustment statistics."""
        return {
            'current_thresholds': self.thresholds.copy(),
            'feedback_count': len(self.feedback_history),
            'category_stats': dict(self.category_stats),
            'overall_agreement': self._calculate_overall_agreement()
        }

    def _calculate_overall_agreement(self) -> float:
        """Calculate overall ML-LLM agreement rate."""
        if not self.feedback_history:
            return 1.0

        agreements = sum(1 for f in self.feedback_history if f.agreement)
        return agreements / len(self.feedback_history)
