"""Contracts and capability helpers for the Elo/MMR monthly ranking system."""

from __future__ import annotations

from dataclasses import asdict, dataclass


CAPABILITY_EXACT = "exact"
CAPABILITY_APPROXIMATE = "approximate"
CAPABILITY_UNAVAILABLE = "not_available"

ACCURACY_EXACT = "exact"
ACCURACY_APPROXIMATE = "approximate"
ACCURACY_PARTIAL = "partial"

DEFAULT_BASE_MMR = 1000.0
ELO_K_FACTOR = 60.0
MIN_VALID_MATCH_DURATION_SECONDS = 900
MIN_VALID_MATCH_PLAYERS = 20
MIN_VALID_PLAYER_PARTICIPATION_SECONDS = 900
MIN_VALID_PLAYER_PARTICIPATION_RATIO = 0.45
FULL_QUALITY_PLAYER_COUNT = 70
FULL_QUALITY_DURATION_SECONDS = 3600
MONTHLY_MIN_VALID_MATCHES = 5
MONTHLY_MIN_TIME_SECONDS = 21600
MONTHLY_ACTIVITY_TARGET_MATCHES = 12
MONTHLY_ACTIVITY_TARGET_HOURS = 20.0
DEFAULT_MONTHLY_SCOREBOARD_MIN_MATCHES = 3


@dataclass(frozen=True, slots=True)
class EloSignalAvailability:
    """Normalized availability state for one scoring input."""

    name: str
    status: str
    detail: str

    def to_dict(self) -> dict[str, object]:
        """Return the availability entry as a serializable mapping."""
        return asdict(self)


def build_signal(name: str, status: str, detail: str) -> dict[str, object]:
    """Create a normalized availability block for one signal."""
    return EloSignalAvailability(name=name, status=status, detail=detail).to_dict()


def summarize_accuracy(signals: list[dict[str, object]]) -> dict[str, object]:
    """Summarize exact, approximate and unavailable signals for one calculation."""
    exact_count = sum(1 for signal in signals if signal.get("status") == CAPABILITY_EXACT)
    approximate_count = sum(
        1 for signal in signals if signal.get("status") == CAPABILITY_APPROXIMATE
    )
    unavailable_count = sum(
        1 for signal in signals if signal.get("status") == CAPABILITY_UNAVAILABLE
    )
    if unavailable_count > 0:
        accuracy_mode = ACCURACY_PARTIAL
    elif approximate_count > 0:
        accuracy_mode = ACCURACY_APPROXIMATE
    else:
        accuracy_mode = ACCURACY_EXACT
    total = max(1, len(signals))
    return {
        "accuracy_mode": accuracy_mode,
        "exact_count": exact_count,
        "approximate_count": approximate_count,
        "unavailable_count": unavailable_count,
        "exact_ratio": round(exact_count / total, 3),
        "approximate_ratio": round(approximate_count / total, 3),
        "unavailable_ratio": round(unavailable_count / total, 3),
        "signals": list(signals),
    }
