"""需求自身先验分：来源内排名归一化后再形成可比分。"""
from __future__ import annotations

from collections import defaultdict
from typing import Any

from supply_infra.scoring.posterior import format_posterior_value
from supply_infra.scoring.ranking import rank_with_scores


DEMAND_PRIORITY_SCORE_METHOD = {
    "name": "source_rank_mean_v1",
    "range": "0-100",
    "steps": [
        "同一需求在同一来源内的非零 weight 先取平均",
        "每个来源内部独立按 weight 降序排名并归一化到 (0,1]",
        "同一需求已有来源的归一分等权平均后乘 100",
    ],
    "missing_source_policy": "未出现的来源不补零",
    "warning": "不同来源的原始 weight 不可直接相加；本分也不可与分类节点 total_score 直接相加",
}


def _average(values: list[float]) -> float | None:
    return sum(values) / len(values) if values else None


def build_demand_priority_index(pool_rows: list[Any]) -> dict[str, dict[str, Any]]:
    """基于一天的完整需求池，构建需求自身的来源可比先验分。"""
    weights: dict[tuple[str, str], list[float]] = defaultdict(list)
    rows_by_name: dict[str, list[Any]] = defaultdict(list)
    observed_strategies: dict[str, set[str]] = defaultdict(set)
    for row in pool_rows:
        demand_name = str(getattr(row, "demand_name", "") or "").strip()
        strategy = str(getattr(row, "strategy", "") or "").strip()
        if not demand_name:
            continue
        rows_by_name[demand_name].append(row)
        if strategy:
            observed_strategies[demand_name].add(strategy)
        raw_weight = getattr(row, "weight", None)
        if strategy and raw_weight is not None and float(raw_weight) != 0:
            weights[(strategy, demand_name)].append(float(raw_weight))

    source_averages = {
        key: float(_average(values))
        for key, values in weights.items()
        if values
    }
    candidates_by_source: dict[str, list[tuple[str, float]]] = defaultdict(list)
    for (strategy, demand_name), avg in source_averages.items():
        candidates_by_source[strategy].append((demand_name, avg))
    positions_by_source = {
        strategy: rank_with_scores(candidates)
        for strategy, candidates in candidates_by_source.items()
    }

    index: dict[str, dict[str, Any]] = {}
    for demand_name, demand_rows in rows_by_name.items():
        sources: list[dict[str, Any]] = []
        for strategy in sorted(observed_strategies[demand_name]):
            avg = source_averages.get((strategy, demand_name))
            position = positions_by_source.get(strategy, {}).get(demand_name)
            source_row_count = sum(
                1
                for row in demand_rows
                if str(getattr(row, "strategy", "") or "").strip() == strategy
            )
            sources.append({
                "strategy": strategy,
                "raw_weight_avg": avg,
                "raw_weight_row_count": source_row_count if avg is not None else 0,
                "rank_in_source": float(position["rank"]) if position is not None else None,
                "source_demand_count": int(position["total"]) if position is not None else 0,
                "source_normalized_rank_score": (
                    float(position["normalized_score"]) if position is not None else None
                ),
            })

        normalized_scores = [
            float(item["source_normalized_rank_score"])
            for item in sources
            if item["source_normalized_rank_score"] is not None
        ]
        prior_score = (
            100 * sum(normalized_scores) / len(normalized_scores)
            if normalized_scores
            else None
        )
        rov_values = [
            float(row.real_rov_7d)
            for row in demand_rows
            if getattr(row, "real_rov_7d", None) is not None
        ]
        vov_values = [
            float(row.real_vov_7d)
            for row in demand_rows
            if getattr(row, "real_vov_7d", None) is not None
        ]
        index[demand_name] = {
            "demand_name": demand_name,
            "source_rank_score": round(prior_score, 4) if prior_score is not None else None,
            "valid_source_count": len(normalized_scores),
            "observed_source_count": len(sources),
            "sources": sources,
            "posterior_from_exact_pool_rows": {
                "rov_diff": {
                    "value": max(rov_values) if rov_values else None,
                    "has_data": bool(rov_values),
                },
                "vov_diff": {
                    "value": max(vov_values) if vov_values else None,
                    "has_data": bool(vov_values),
                },
            },
            "exact_pool_ids": sorted({int(row.id) for row in demand_rows}),
        }

    demand_positions = rank_with_scores([
        (demand_name, float(item["source_rank_score"]))
        for demand_name, item in index.items()
        if item["source_rank_score"] is not None
    ])
    for demand_name, item in index.items():
        position = demand_positions.get(demand_name)
        item["global_demand_rank"] = float(position["rank"]) if position is not None else None
        item["global_scored_demand_count"] = int(position["total"]) if position is not None else 0
        item["score_method"] = DEMAND_PRIORITY_SCORE_METHOD["name"]
    return index


def format_demand_priority(item: dict[str, Any] | None) -> list[str]:
    """将需求自身排名证据格式化为 Agent 易读文本。"""
    if item is None:
        return ["需求自身来源归一分=—（无需求池记录）"]
    score = item.get("source_rank_score")
    rank = item.get("global_demand_rank")
    total = int(item.get("global_scored_demand_count") or 0)
    score_text = "—" if score is None else f"{float(score):.2f}/100"
    rank_text = "无排名" if rank is None else f"{float(rank):g}/{total}"
    lines = [
        f"需求自身来源归一分={score_text}；全日需求自身排名={rank_text}；"
        f"有效来源={int(item.get('valid_source_count') or 0)}",
    ]
    for source in item.get("sources") or []:
        raw = source.get("raw_weight_avg")
        source_rank = source.get("rank_in_source")
        normalized = source.get("source_normalized_rank_score")
        raw_text = "—" if raw is None else f"{float(raw):.4f}"
        source_rank_text = (
            "—"
            if source_rank is None
            else f"{float(source_rank):g}/{source['source_demand_count']}"
        )
        normalized_text = "—" if normalized is None else f"{float(normalized):.4f}"
        lines.append(
            f"  来源={source['strategy']} raw_weight_avg={raw_text} "
            f"来源内名次={source_rank_text} 来源归一分={normalized_text}"
        )
    lines.append("  口径：来源内先排名归一化，再对已有来源取均值；禁止直接相加原始 weight。")
    posterior = item.get("posterior_from_exact_pool_rows") or {}
    rov = posterior.get("rov_diff") or {}
    vov = posterior.get("vov_diff") or {}
    if rov.get("has_data") or vov.get("has_data"):
        lines.append(
            "  词级后验："
            f"rov_diff={format_posterior_value(rov.get('value'))} "
            f"vov_diff={format_posterior_value(vov.get('value'))}"
        )
    else:
        lines.append("  词级后验：无验证数据(效果未知)")
    return lines
