"""Dynamic importance scoring for adaptive retrieval.

Computes a fact's dynamic importance from base importance, retrieval history,
recency of use, user corrections, and pattern membership. Inspired by
cognitive memory strength models.
"""

from __future__ import annotations

import math
from datetime import UTC, datetime

__all__ = ["compute_dynamic_importance"]


def compute_dynamic_importance(
    base_importance: float,
    times_retrieved: int,
    last_retrieved_at: datetime | None,
    user_correction_count: int,
    is_in_active_pattern: bool,
    now: datetime | None = None,
) -> float:
    """Compute dynamic importance score for a memory fact.

    New facts start with base_importance=0.5 (from LLM extraction).
    Importance grows organically through retrieval practice, recency of use,
    and pattern membership. Called during the READ path (spreading activation).

    Components:
        - retrieval_boost: log(1 + times_retrieved) — saturates gradually
        - recency_of_use_boost: decays from last_retrieved_at (half-life 7 days)
        - correction_penalty: 0.8^n for each user correction
        - pattern_boost: 1.3x if fact is part of an active meta-observation

    Args:
        base_importance: Base importance score (typically 0.5).
        times_retrieved: Number of times this fact has been retrieved.
        last_retrieved_at: When the fact was last retrieved.
        user_correction_count: Number of user corrections on this fact.
        is_in_active_pattern: Whether fact is part of an active meta-observation.
        now: Current timestamp (defaults to UTC now).

    Returns:
        Dynamic importance score, clamped to [0.05, 3.0].
    """
    if now is None:
        now = datetime.now(UTC)

    # 1. Retrieval practice boost: log(1 + n), normalized to ~0-1 range
    retrieval_boost = math.log(1 + times_retrieved) / math.log(11)

    # 2. Recency of use: exponential decay, half-life of 7 days
    use_recency_boost = 0.0
    if last_retrieved_at:
        if last_retrieved_at.tzinfo is None:
            last_retrieved_at = last_retrieved_at.replace(tzinfo=UTC)
        age_days = max(0, (now - last_retrieved_at).total_seconds() / 86400)
        use_recency_boost = 0.5 ** (age_days / 7.0)

    # 3. Correction penalty: 0.8^n — each correction reduces by 20%
    correction_penalty = 0.8 ** min(user_correction_count, 5)

    # 4. Pattern membership boost
    pattern_boost = 1.3 if is_in_active_pattern else 1.0

    # Combine
    dynamic = (
        base_importance * (1.0 + 0.3 * retrieval_boost + 0.2 * use_recency_boost) * correction_penalty * pattern_boost
    )

    return max(0.05, min(3.0, dynamic))
