"""重要性评估器

评估特征重要性相对于噪音的统计显著性，执行交叉淘汰。
"""

from typing import Dict, List, Optional, Tuple


class ImportanceEvaluator:
    """重要性评估器

    计算噪音及格线，执行交叉淘汰。
    强制使用 Gain 重要性，避免被噪音欺骗。
    """

    def __init__(self, noise_prefix: str = "__noise__"):
        """初始化评估器

        Args:
            noise_prefix: 噪音列名前缀
        """
        self.noise_prefix = noise_prefix
        self.regression_threshold: Optional[float] = None
        self.classification_threshold: Optional[float] = None
        self.elimination_stats: dict = {}

    def evaluate(
        self,
        regression_importance: Dict[str, float],
        classification_importance: Dict[str, float],
        candidate_features: List[str],
    ) -> List[str]:
        """执行重要性评估和交叉淘汰

        Args:
            regression_importance: 回归模型特征重要性 {feature: importance}
            classification_importance: 分类模型特征重要性 {feature: importance}
            candidate_features: 候选特征列表（不包含噪音）

        Returns:
            存活下来的特征列表
        """
        # 计算及格线（噪音重要性的最大值）
        self.regression_threshold = self._calculate_threshold(regression_importance)
        self.classification_threshold = self._calculate_threshold(
            classification_importance
        )

        # 执行交叉淘汰
        eliminated = []
        survived = []

        for feature in candidate_features:
            reg_imp = regression_importance.get(feature, 0.0)
            cls_imp = classification_importance.get(feature, 0.0)

            # 交叉淘汰：两个模型都低于及格线才剔除
            if (
                reg_imp < self.regression_threshold
                and cls_imp < self.classification_threshold
            ):
                eliminated.append(
                    {
                        "feature": feature,
                        "regression_importance": reg_imp,
                        "classification_importance": cls_imp,
                        "regression_threshold": self.regression_threshold,
                        "classification_threshold": self.classification_threshold,
                    }
                )
            else:
                survived.append(feature)

        self.elimination_stats = {
            "total_candidates": len(candidate_features),
            "eliminated_count": len(eliminated),
            "survived_count": len(survived),
            "regression_threshold": self.regression_threshold,
            "classification_threshold": self.classification_threshold,
            "eliminated_features": eliminated,
        }

        return survived

    def _calculate_threshold(self, importance: Dict[str, float]) -> float:
        """计算噪音及格线

        取所有噪音特征重要性的最大值作为及格线。

        Args:
            importance: 特征重要性字典

        Returns:
            及格线数值
        """
        noise_importance = [
            imp
            for feat, imp in importance.items()
            if feat.startswith(self.noise_prefix)
        ]

        if not noise_importance:
            # 如果没有噪音特征，返回一个很小的值（不应该发生）
            return 0.0

        return max(noise_importance)

    def get_thresholds(self) -> Tuple[Optional[float], Optional[float]]:
        """获取及格线

        Returns:
            (回归及格线, 分类及格线) 元组
        """
        return self.regression_threshold, self.classification_threshold

    def get_elimination_stats(self) -> dict:
        """获取淘汰统计

        Returns:
            淘汰统计字典
        """
        return self.elimination_stats

    def get_feature_comparison(
        self,
        regression_importance: Dict[str, float],
        classification_importance: Dict[str, float],
        candidate_features: List[str],
    ) -> List[Dict]:
        """获取所有特征的重要性对比详情

        Args:
            regression_importance: 回归重要性
            classification_importance: 分类重要性
            candidate_features: 候选特征

        Returns:
            特征对比列表，每项包含：
            - feature: 特征名
            - regression_importance: 回归重要性
            - classification_importance: 分类重要性
            - regression_threshold: 回归及格线
            - classification_threshold: 分类及格线
            - is_eliminated: 是否被淘汰
            - elimination_reason: 淘汰原因
        """
        comparison = []

        for feature in candidate_features:
            reg_imp = regression_importance.get(feature, 0.0)
            cls_imp = classification_importance.get(feature, 0.0)

            # 判断是否被淘汰
            is_eliminated = (
                reg_imp < self.regression_threshold
                and cls_imp < self.classification_threshold
            )

            # 生成淘汰原因
            reasons = []
            if reg_imp < self.regression_threshold:
                reasons.append(
                    f"回归重要性({reg_imp:.6f})低于及格线({self.regression_threshold:.6f})"
                )
            if cls_imp < self.classification_threshold:
                reasons.append(
                    f"分类重要性({cls_imp:.6f})低于及格线({self.classification_threshold:.6f})"
                )

            comparison.append(
                {
                    "feature": feature,
                    "regression_importance": reg_imp,
                    "classification_importance": cls_imp,
                    "regression_threshold": self.regression_threshold,
                    "classification_threshold": self.classification_threshold,
                    "is_eliminated": is_eliminated,
                    "elimination_reason": "; ".join(reasons) if reasons else "通过筛选",
                }
            )

        # 按重要性总和排序
        comparison.sort(
            key=lambda x: x["regression_importance"] + x["classification_importance"],
            reverse=True,
        )

        return comparison
