"""Fundamental value-type categories for Component values.

These ABCs define the resolution dispatch in :meth:`OHR.resolve`:

* **Point** — absolute value (pitch, position).  Does not resolve further.
* **Vector** — relative value (interval).  Resolves against a component
  (``point + vector``).
* **Selector** — positional/relational reference into a collection.
  Resolves against a reference collection (OHR body).

Paradigm-specific types (e.g. pitchspace's SPC, SIC) subclass Point and
Vector respectively.  Selector subclasses include ScaleDegree and
IntervalSelector (planned).
"""

from abc import ABC, abstractmethod
from numbers import Number
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from flexohr.core.ohr import OHR


class AbstractNumber(ABC, Number):
    """Root ABC for numeric value types (Points and Vectors)."""


class Point(AbstractNumber):
    """Absolute value — does not resolve further."""


class Vector(AbstractNumber):
    """Relative value — resolves by adding to a Point."""


class Selector(ABC):
    """Value that resolves by selecting from a reference OHR.

    Subclasses must implement :meth:`resolve_against`.
    """

    @abstractmethod
    def resolve_against(self, ohr: "OHR") -> "Point | Vector":
        """Resolve this selector against a reference OHR.

        Parameters
        ----------
        ohr : OHR
            The reference OHR (e.g. a Scale).

        Returns
        -------
        The resolved value (type depends on the OHR and selector).

        Raises
        ------
        NotImplementedError
            Subclasses must override this method.
        """
        raise NotImplementedError(f"{type(self).__name__}.resolve_against() not implemented")
