"""Hotness scoring for cold/hot memory lifecycle management.

Pure function — ``score = log1p(active_count)/(log1p(active_count)+1) * exp_decay(age)``.

freq range is [0.0, 1.0): 0 when never accessed, approaches 1 as access count grows.
"""

from __future__ import annotations

import math
from datetime import datetime, timezone

DEFAULT_HALF_LIFE_DAYS: float = 7.0


def hotness_score(
    active_count: int,
    updated_at: datetime | None,
    *,
    now: datetime | None = None,
    half_life_days: float = DEFAULT_HALF_LIFE_DAYS,
) -> float:
    if now is None:
        now = datetime.now(timezone.utc)

    freq = math.log1p(max(active_count, 0)) / (math.log1p(max(active_count, 0)) + 1)

    if updated_at is None:
        return 0.0

    if updated_at.tzinfo is None:
        updated_at = updated_at.replace(tzinfo=timezone.utc)
    if now.tzinfo is None:
        now = now.replace(tzinfo=timezone.utc)

    age_days = max((now - updated_at).total_seconds() / 86_400.0, 0.0)
    decay_rate = math.log(2) / max(half_life_days, 1e-9)
    recency = math.exp(-decay_rate * age_days)

    return freq * recency