"""跨业务模块复用的排名归一化工具。"""
from __future__ import annotations

from collections.abc import Hashable
from typing import TypeVar


KeyT = TypeVar("KeyT", bound=Hashable)


def rank_with_scores(items: list[tuple[KeyT, float]]) -> dict[KeyT, dict[str, float | int]]:
    """按值降序排名，并返回同分平均名次与 ``(0, 1]`` 排名分。

    不同量纲的数据应先分别调用本函数，不能先把原始值相加。排名分公式与
    ``category_tree_weight`` 的四维全局排名口径一致：
    ``score = (n - avg_rank + 1) / n``。
    """
    if not items:
        return {}

    sorted_items = sorted(items, key=lambda item: (-item[1], str(item[0])))
    total = len(sorted_items)
    result: dict[KeyT, dict[str, float | int]] = {}
    start = 0
    while start < total:
        end = start
        value = sorted_items[start][1]
        while end < total and sorted_items[end][1] == value:
            end += 1
        average_rank = (start + 1 + end) / 2.0
        normalized_score = (total - average_rank + 1) / total
        for index in range(start, end):
            result[sorted_items[index][0]] = {
                "rank": average_rank,
                "total": total,
                "normalized_score": normalized_score,
            }
        start = end
    return result


def rank_to_scores(items: list[tuple[KeyT, float]]) -> dict[KeyT, float]:
    """兼容原调用方：只返回排名归一分。"""
    return {
        key: float(position["normalized_score"])
        for key, position in rank_with_scores(items).items()
    }
