"""
Enhanced dual confidence strategy with early rejection of candidates.
"""

from loguru import logger

from ..constraint_checking import DualConfidenceChecker
from .dual_confidence_strategy import DualConfidenceStrategy


class DualConfidenceWithRejectionStrategy(DualConfidenceStrategy):
    """
    Enhanced dual confidence strategy that rejects candidates early when they have
    high negative evidence for any constraint.
    """

    def __init__(
        self,
        *args,
        rejection_threshold: float = 0.3,  # If negative > 30% and positive < threshold
        positive_threshold: float = 0.2,  # Minimum positive needed to overcome negative
        critical_constraint_rejection: float = 0.2,  # Even stricter for critical constraints
        **kwargs,
    ):
        super().__init__(*args, **kwargs)
        self.rejection_threshold = rejection_threshold
        self.positive_threshold = positive_threshold
        self.critical_constraint_rejection = critical_constraint_rejection

        # Initialize constraint checker (using new inheritance-based system)
        self.constraint_checker = DualConfidenceChecker(
            model=self.model,
            evidence_gatherer=self._gather_evidence_for_constraint,
            negative_threshold=0.25,  # 25% negative evidence threshold
            positive_threshold=0.4,  # 40% minimum positive evidence
            uncertainty_penalty=self.uncertainty_penalty,
            negative_weight=self.negative_weight,
        )

    def _evaluate_candidate_immediately(self, candidate) -> float:
        """Enhanced evaluation with early rejection based on negative evidence."""
        try:
            logger.info(
                f"Evaluating candidate: {candidate.name} with early rejection"
            )

            total_score = 0.0
            constraint_scores = []
            detailed_results = []

            for i, constraint in enumerate(self.constraint_ranking):
                # Gather evidence for this constraint
                evidence = self._gather_evidence_for_constraint(
                    candidate, constraint
                )

                if evidence:
                    # Analyze evidence with dual confidence
                    dual_evidence = [
                        self._analyze_evidence_dual_confidence(e, constraint)
                        for e in evidence
                    ]

                    # Calculate average scores
                    avg_positive = sum(
                        e.positive_confidence for e in dual_evidence
                    ) / len(dual_evidence)
                    avg_negative = sum(
                        e.negative_confidence for e in dual_evidence
                    ) / len(dual_evidence)
                    avg_uncertainty = sum(
                        e.uncertainty for e in dual_evidence
                    ) / len(dual_evidence)

                    # EARLY REJECTION LOGIC
                    # Reject if negative evidence is above 25% - simplified approach
                    if avg_negative > 0.25:
                        logger.info(
                            f"❌ EARLY REJECTION: {candidate.name} - Constraint '{constraint.value}' "
                            f"has significant negative evidence ({avg_negative:.0%})"
                        )
                        return 0.0  # Immediate rejection

                    # If high negative but also decent positive, continue but penalize
                    if (
                        avg_negative > self.rejection_threshold
                        and avg_positive > self.positive_threshold
                    ):
                        logger.warning(
                            f"⚠️ Mixed evidence for {candidate.name} - {constraint.value}: "
                            f"+{avg_positive:.0%} -{avg_negative:.0%}"
                        )

                    # Calculate score using parent method
                    score = self._evaluate_evidence(evidence, constraint)
                    constraint_scores.append(score)

                    detailed_results.append(
                        {
                            "constraint": constraint.value,
                            "score": score,
                            "positive": avg_positive,
                            "negative": avg_negative,
                            "uncertainty": avg_uncertainty,
                            "weight": constraint.weight,
                        }
                    )

                    # Visual feedback
                    symbol = (
                        "✓" if score >= 0.8 else "○" if score >= 0.5 else "✗"
                    )
                    logger.info(
                        f"{symbol} {candidate.name} | {constraint.value}: {int(score * 100)}% "
                        f"(+{int(avg_positive * 100)}% -{int(avg_negative * 100)}% ?{int(avg_uncertainty * 100)}%)"
                    )

                    # Skip remaining constraints if this one failed badly
                    if score < 0.2 and constraint.weight > 0.5:
                        logger.info(
                            "⚠️ Skipping remaining constraints due to poor score on important constraint"
                        )
                        break
                else:
                    # No evidence - high uncertainty
                    score = 0.5 - self.uncertainty_penalty
                    constraint_scores.append(score)
                    logger.info(
                        f"? {candidate.name} | {constraint.value}: No evidence found"
                    )

            # Calculate weighted average
            if constraint_scores:
                weights = [
                    c.weight
                    for c in self.constraint_ranking[: len(constraint_scores)]
                ]
                total_score = sum(
                    s * w
                    for s, w in zip(constraint_scores, weights, strict=False)
                ) / sum(weights)

            # Log detailed breakdown
            logger.info(f"\nDetailed analysis for {candidate.name}:")
            for result in detailed_results:
                logger.info(
                    f"  {result['constraint']}: {result['score']:.2%} "
                    f"(+{result['positive']:.0%} -{result['negative']:.0%} ?{result['uncertainty']:.0%}) "
                    f"[weight: {result['weight']:.1f}]"
                )

            logger.info(f"Final score for {candidate.name}: {total_score:.2%}")

            # Store constraint evaluation results on the candidate object
            candidate.evaluation_results = detailed_results
            candidate.score = total_score

            # Update tracking
            with self.evaluation_lock:
                self.evaluated_candidates[candidate.name] = total_score

                if total_score > self.best_score:
                    self.best_score = total_score
                    self.best_candidate = candidate
                    logger.info(
                        f"New best: {candidate.name} with {total_score:.2%}"
                    )

                    # Check for early stop
                    if total_score >= self.early_stop_threshold:
                        logger.info(
                            f"🎯 EARLY STOP: {candidate.name} reached {total_score:.2%}!"
                        )
                        self.found_answer.set()

            return total_score

        except Exception:
            logger.exception(f"Error evaluating {candidate.name}")
            return 0.0

    def _evaluate_candidate_with_constraint_checker(self, candidate) -> float:
        """
        Evaluate candidate using the new modular constraint checking system.

        This method can be used as an alternative to the existing evaluation logic.
        """
        try:
            # Use the constraint checker
            result = self.constraint_checker.check_candidate(
                candidate, self.constraint_ranking
            )

            # Store results on candidate
            candidate.evaluation_results = result.detailed_results
            candidate.score = result.total_score

            # Update tracking
            with self.evaluation_lock:
                self.evaluated_candidates[candidate.name] = result.total_score

                if result.total_score > self.best_score:
                    self.best_score = result.total_score
                    self.best_candidate = candidate
                    logger.info(
                        f"New best: {candidate.name} with {result.total_score:.2%}"
                    )

                    # Check for early stop
                    if result.total_score >= self.early_stop_threshold:
                        logger.info(
                            f"🎯 EARLY STOP: {candidate.name} reached {result.total_score:.2%}!"
                        )
                        self.found_answer.set()

            return result.total_score

        except Exception:
            logger.exception(f"Error evaluating {candidate.name}")
            return 0.0
