"""
Recency Scorer for Context Management.

Scores context based on how recent it is.
More recent content gets higher scores.
"""

import math
from datetime import UTC, datetime
from typing import Any

from ..types import BaseContext, ContextType
from .base import BaseScorer


class RecencyScorer(BaseScorer):
    """
    Scores context based on recency.

    Uses exponential decay to score content based on age.
    More recent content scores higher.
    """

    def __init__(
        self,
        weight: float = 1.0,
        half_life_hours: float = 24.0,
        type_half_lives: dict[ContextType, float] | None = None,
    ) -> None:
        """
        Initialize recency scorer.

        Args:
            weight: Scorer weight for composite scoring
            half_life_hours: Default hours until score decays to 0.5
            type_half_lives: Optional context-type-specific half lives
        """
        super().__init__(weight)
        self._half_life_hours = half_life_hours
        self._type_half_lives = type_half_lives or {}

        # Set sensible defaults for context types
        if ContextType.CONVERSATION not in self._type_half_lives:
            self._type_half_lives[ContextType.CONVERSATION] = 1.0  # 1 hour
        if ContextType.TOOL not in self._type_half_lives:
            self._type_half_lives[ContextType.TOOL] = 0.5  # 30 minutes
        if ContextType.KNOWLEDGE not in self._type_half_lives:
            self._type_half_lives[ContextType.KNOWLEDGE] = 168.0  # 1 week
        if ContextType.SYSTEM not in self._type_half_lives:
            self._type_half_lives[ContextType.SYSTEM] = 720.0  # 30 days
        if ContextType.TASK not in self._type_half_lives:
            self._type_half_lives[ContextType.TASK] = 24.0  # 1 day

    async def score(
        self,
        context: BaseContext,
        query: str,
        **kwargs: Any,
    ) -> float:
        """
        Score context based on recency.

        Args:
            context: Context to score
            query: Query (not used for recency, kept for interface)
            **kwargs: Additional parameters
                - reference_time: Time to measure recency from (default: now)

        Returns:
            Recency score between 0.0 and 1.0
        """
        reference_time = kwargs.get("reference_time")
        if reference_time is None:
            reference_time = datetime.now(UTC)
        elif reference_time.tzinfo is None:
            reference_time = reference_time.replace(tzinfo=UTC)

        # Ensure context timestamp is timezone-aware
        context_time = context.timestamp
        if context_time.tzinfo is None:
            context_time = context_time.replace(tzinfo=UTC)

        # Calculate age in hours
        age = reference_time - context_time
        age_hours = max(0, age.total_seconds() / 3600)

        # Get half-life for this context type
        context_type = context.get_type()
        half_life = self._type_half_lives.get(context_type, self._half_life_hours)

        # Exponential decay
        decay_factor = math.exp(-math.log(2) * age_hours / half_life)

        return self.normalize_score(decay_factor)

    def get_half_life(self, context_type: ContextType) -> float:
        """
        Get half-life for a context type.

        Args:
            context_type: Context type to get half-life for

        Returns:
            Half-life in hours
        """
        return self._type_half_lives.get(context_type, self._half_life_hours)

    def set_half_life(self, context_type: ContextType, hours: float) -> None:
        """
        Set half-life for a context type.

        Args:
            context_type: Context type to set half-life for
            hours: Half-life in hours
        """
        if hours <= 0:
            raise ValueError("Half-life must be positive")
        self._type_half_lives[context_type] = hours

    async def score_batch(
        self,
        contexts: list[BaseContext],
        query: str,
        **kwargs: Any,
    ) -> list[float]:
        """
        Score multiple contexts.

        Args:
            contexts: Contexts to score
            query: Query (not used)
            **kwargs: Additional parameters

        Returns:
            List of scores (same order as input)
        """
        scores = []
        for context in contexts:
            score = await self.score(context, query, **kwargs)
            scores.append(score)
        return scores
