"""Monthly MVP V1 scoring helpers."""

from __future__ import annotations

import math
from typing import Mapping


MONTHLY_MVP_VERSION = "v1"
MONTHLY_MVP_MIN_MATCHES = 6
MONTHLY_MVP_MIN_TIME_SECONDS = 21600
MONTHLY_MVP_FULL_PARTICIPATION_SECONDS = 28800
MONTHLY_MVP_TEAMKILL_PENALTY_CAP = 6.0
MONTHLY_MVP_TEAMKILL_PENALTY_PER_KILL = 0.5


def build_monthly_mvp_rankings(
    aggregated_rows: list[Mapping[str, object]],
    *,
    limit: int,
) -> dict[str, object]:
    """Transform aggregated monthly totals into ranked MVP V1 items."""
    eligible_rows = [
        _build_eligible_player_summary(row)
        for row in aggregated_rows
        if _is_eligible_player_row(row)
    ]

    if not eligible_rows:
        return {
            "ranking_version": MONTHLY_MVP_VERSION,
            "eligibility": _build_eligibility_metadata(),
            "items": [],
            "eligible_players_count": 0,
        }

    max_total_kills = max(item["totals"]["kills"] for item in eligible_rows)
    max_total_support = max(item["totals"]["support"] for item in eligible_rows)
    max_kpm = max(item["derived"]["kpm"] for item in eligible_rows)
    max_kda = max(item["derived"]["kda"] for item in eligible_rows)

    for item in eligible_rows:
        component_scores = {
            "kills_score": _log_normalized_score(item["totals"]["kills"], max_total_kills),
            "support_score": _log_normalized_score(item["totals"]["support"], max_total_support),
            "kpm_score": _log_normalized_score(item["derived"]["kpm"], max_kpm),
            "kda_score": _log_normalized_score(item["derived"]["kda"], max_kda),
            "participation_score": round(
                100
                * min(
                    1.0,
                    item["totals"]["time_seconds"] / MONTHLY_MVP_FULL_PARTICIPATION_SECONDS,
                ),
                3,
            ),
        }
        teamkill_penalty = round(
            min(
                MONTHLY_MVP_TEAMKILL_PENALTY_CAP,
                item["totals"]["teamkills"] * MONTHLY_MVP_TEAMKILL_PENALTY_PER_KILL,
            ),
            3,
        )
        item["component_scores"] = component_scores
        item["teamkill_penalty"] = teamkill_penalty
        item["mvp_score"] = round(
            (0.35 * component_scores["kills_score"])
            + (0.20 * component_scores["support_score"])
            + (0.20 * component_scores["kpm_score"])
            + (0.15 * component_scores["kda_score"])
            + (0.10 * component_scores["participation_score"])
            - teamkill_penalty,
            3,
        )

    ranked_items = sorted(
        eligible_rows,
        key=lambda item: (
            -item["mvp_score"],
            -item["component_scores"]["participation_score"],
            -item["component_scores"]["kills_score"],
            -item["component_scores"]["support_score"],
            item["totals"]["teamkills"],
            str(item["player"]["name"]).casefold(),
            str(item["player"]["stable_player_key"]),
        ),
    )
    for position, item in enumerate(ranked_items[:limit], start=1):
        item["ranking_position"] = position

    return {
        "ranking_version": MONTHLY_MVP_VERSION,
        "eligibility": _build_eligibility_metadata(),
        "eligible_players_count": len(eligible_rows),
        "items": ranked_items[:limit],
    }


def _is_eligible_player_row(row: Mapping[str, object]) -> bool:
    matches_count = int(row.get("matches_count") or 0)
    time_seconds = int(row.get("total_time_seconds") or 0)
    has_required_fields = all(
        row.get(field_name) is not None
        for field_name in ("total_kills", "total_deaths", "total_support", "total_time_seconds")
    )
    return (
        has_required_fields
        and matches_count >= MONTHLY_MVP_MIN_MATCHES
        and time_seconds >= MONTHLY_MVP_MIN_TIME_SECONDS
    )


def _build_eligible_player_summary(row: Mapping[str, object]) -> dict[str, object]:
    total_kills = int(row.get("total_kills") or 0)
    total_deaths = int(row.get("total_deaths") or 0)
    total_support = int(row.get("total_support") or 0)
    total_teamkills = int(row.get("total_teamkills") or 0)
    total_time_seconds = int(row.get("total_time_seconds") or 0)
    total_time_minutes = max(total_time_seconds / 60.0, 1.0)
    kpm = round(total_kills / total_time_minutes, 6)
    kda = round(total_kills / max(total_deaths, 1), 6)
    return {
        "server": {
            "slug": row.get("server_slug"),
            "name": row.get("server_name"),
        },
        "player": {
            "stable_player_key": row.get("stable_player_key"),
            "name": row.get("player_name"),
            "steam_id": row.get("steam_id"),
        },
        "matches_considered": int(row.get("matches_count") or 0),
        "totals": {
            "kills": total_kills,
            "deaths": total_deaths,
            "support": total_support,
            "teamkills": total_teamkills,
            "time_seconds": total_time_seconds,
            "time_minutes": round(total_time_seconds / 60.0, 2),
        },
        "derived": {
            "kpm": kpm,
            "kda": kda,
        },
    }


def _log_normalized_score(value: float | int, max_value: float | int) -> float:
    if value <= 0 or max_value <= 0:
        return 0.0
    return round((100 * math.log1p(value)) / math.log1p(max_value), 3)


def _build_eligibility_metadata() -> dict[str, object]:
    return {
        "minimum_matches": MONTHLY_MVP_MIN_MATCHES,
        "minimum_time_seconds": MONTHLY_MVP_MIN_TIME_SECONDS,
        "minimum_time_hours": round(MONTHLY_MVP_MIN_TIME_SECONDS / 3600, 1),
        "full_participation_seconds": MONTHLY_MVP_FULL_PARTICIPATION_SECONDS,
        "full_participation_hours": round(MONTHLY_MVP_FULL_PARTICIPATION_SECONDS / 3600, 1),
        "teamkill_penalty_per_kill": MONTHLY_MVP_TEAMKILL_PENALTY_PER_KILL,
        "teamkill_penalty_cap": MONTHLY_MVP_TEAMKILL_PENALTY_CAP,
    }
