"""Direct age standardisation (L3-2).

Puts a study group's age-specific rates onto the Class 4
earliest-2024-NT known-age band distribution.

Returns a fraction, or None when any required band is missing.
Do not overwrite by_age_fail.json. Do not feed the result to
wilson_interval as if it were successes/n.
"""

from __future__ import annotations

from collections.abc import Mapping
from typing import Any

AGE_BANDS: tuple[str, ...] = ("3-5", "5-8", "8-12", "12-16", "16+")


def standardise(
    counts: Mapping[str, Mapping[str, Any]],
    weights: Mapping[str, float],
) -> float | None:
    """Directly standardise age-specific rates onto `weights`.

    ``counts`` is ``{band: {cohort, events}}``. ``weights`` is
    ``{band: weight}`` — either the standard population's band shares
    or the raw standard counts. The five ``AGE_BANDS`` must all be
    present in both maps. A missing band returns ``None``; the
    remaining bands are not re-weighted.

    The result is a fraction, not a percent. It is not a binomial
    proportion and must not be fed to ``wilson_interval`` as if
    ``n`` were the study total.
    """
    weighted = 0.0
    weight_sum = 0.0
    for band in AGE_BANDS:
        if band not in counts or band not in weights:
            return None
        cell = counts[band]
        if cell is None:
            return None
        try:
            cohort = cell["cohort"]
            events = cell["events"]
        except (KeyError, TypeError):
            return None
        if cohort is None or events is None:
            return None
        cohort = int(cohort)
        events = int(events)
        if cohort < 1:
            return None
        if events < 0 or events > cohort:
            raise ValueError("events must be in [0, cohort]")
        weight = float(weights[band])
        if weight < 0:
            raise ValueError("weight must be non-negative")
        weighted += (events / cohort) * weight
        weight_sum += weight
    if weight_sum <= 0:
        return None
    return weighted / weight_sum
