"""
Rejection engine for constraint-based candidate filtering.

This module provides logic for rejecting candidates based on constraint violations.
"""

from dataclasses import dataclass
from typing import Dict, List, Optional

from loguru import logger

from ..candidates.base_candidate import Candidate
from ..constraints.base_constraint import Constraint
from .evidence_analyzer import ConstraintEvidence


@dataclass
class RejectionResult:
    """Result of a rejection check."""

    should_reject: bool
    reason: str
    constraint_value: str
    positive_confidence: float
    negative_confidence: float


class RejectionEngine:
    """
    Engine for making rejection decisions based on constraint violations.

    This engine uses simple, clear rules to determine when candidates
    should be rejected based on their constraint evaluation results.
    """

    def __init__(
        self,
        negative_threshold: float = 0.25,  # Reject if negative evidence > 25%
        positive_threshold: float = 0.4,  # Reject if positive evidence < 40%
    ):
        """
        Initialize the rejection engine.

        Args:
            negative_threshold: Threshold for negative evidence rejection
            positive_threshold: Minimum positive evidence required
        """
        self.negative_threshold = negative_threshold
        self.positive_threshold = positive_threshold

    def should_reject_candidate(
        self,
        candidate: Candidate,
        constraint: Constraint,
        evidence_list: List[ConstraintEvidence],
    ) -> RejectionResult:
        """
        Determine if a candidate should be rejected based on constraint evidence.

        Args:
            candidate: The candidate being evaluated
            constraint: The constraint being checked
            evidence_list: List of evidence for this constraint

        Returns:
            RejectionResult: Whether to reject and why
        """
        if not evidence_list:
            # No evidence - don't reject but note the lack of evidence
            return RejectionResult(
                should_reject=False,
                reason="No evidence available",
                constraint_value=constraint.value,
                positive_confidence=0.0,
                negative_confidence=0.0,
            )

        # Calculate average confidence scores
        avg_positive = sum(e.positive_confidence for e in evidence_list) / len(
            evidence_list
        )
        avg_negative = sum(e.negative_confidence for e in evidence_list) / len(
            evidence_list
        )

        # PRIMARY REJECTION RULE: High negative evidence
        if avg_negative > self.negative_threshold:
            return RejectionResult(
                should_reject=True,
                reason=f"High negative evidence ({avg_negative:.0%})",
                constraint_value=constraint.value,
                positive_confidence=avg_positive,
                negative_confidence=avg_negative,
            )

        # SECONDARY REJECTION RULE: Low positive evidence
        if avg_positive < self.positive_threshold:
            return RejectionResult(
                should_reject=True,
                reason=f"Insufficient positive evidence ({avg_positive:.0%})",
                constraint_value=constraint.value,
                positive_confidence=avg_positive,
                negative_confidence=avg_negative,
            )

        # No rejection needed
        return RejectionResult(
            should_reject=False,
            reason="Constraints satisfied",
            constraint_value=constraint.value,
            positive_confidence=avg_positive,
            negative_confidence=avg_negative,
        )

    def check_all_constraints(
        self,
        candidate: Candidate,
        constraint_results: Dict[Constraint, List[ConstraintEvidence]],
    ) -> Optional[RejectionResult]:
        """
        Check all constraints for a candidate and return first rejection reason.

        Args:
            candidate: The candidate being evaluated
            constraint_results: Dictionary mapping constraints to their evidence

        Returns:
            RejectionResult if should reject, None if should accept
        """
        for constraint, evidence_list in constraint_results.items():
            result = self.should_reject_candidate(
                candidate, constraint, evidence_list
            )

            if result.should_reject:
                logger.info(
                    f"❌ REJECTION: {candidate.name} - {constraint.value} - {result.reason}"
                )
                return result

        # No rejections found
        logger.info(f"✓ ACCEPTED: {candidate.name} - All constraints satisfied")
        return None
