"""
Base Scorer Protocol and Types.

Defines the interface for context scoring implementations.
"""

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable

from ..types import BaseContext

if TYPE_CHECKING:
    pass


@runtime_checkable
class ScorerProtocol(Protocol):
    """Protocol for context scorers."""

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

        Args:
            context: Context to score
            query: Query to score against
            **kwargs: Additional scoring parameters

        Returns:
            Score between 0.0 and 1.0
        """
        ...


class BaseScorer(ABC):
    """
    Abstract base class for context scorers.

    Provides common functionality and interface for
    different scoring strategies.
    """

    def __init__(self, weight: float = 1.0) -> None:
        """
        Initialize scorer.

        Args:
            weight: Weight for this scorer in composite scoring
        """
        self._weight = weight

    @property
    def weight(self) -> float:
        """Get scorer weight."""
        return self._weight

    @weight.setter
    def weight(self, value: float) -> None:
        """Set scorer weight."""
        if not 0.0 <= value <= 1.0:
            raise ValueError("Weight must be between 0.0 and 1.0")
        self._weight = value

    @abstractmethod
    async def score(
        self,
        context: BaseContext,
        query: str,
        **kwargs: Any,
    ) -> float:
        """
        Score a context item.

        Args:
            context: Context to score
            query: Query to score against
            **kwargs: Additional scoring parameters

        Returns:
            Score between 0.0 and 1.0
        """
        ...

    def normalize_score(self, score: float) -> float:
        """
        Normalize score to [0.0, 1.0] range.

        Args:
            score: Raw score

        Returns:
            Normalized score
        """
        return max(0.0, min(1.0, score))
