"""Indicator base: pure function from market data to derived series."""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Generic, TypeVar

import numpy as np
from numpy.typing import NDArray

T = TypeVar("T", bound=NDArray[np.float64])


class Indicator(ABC, Generic[T]):
    """
    Pure function from market data to derived series.

    Stateless: same inputs always yield same outputs. Output same length as
    input; use np.nan where lookback is insufficient.
    """

    @property
    @abstractmethod
    def name(self) -> str:
        """Human-readable indicator name."""
        pass

    @property
    @abstractmethod
    def lookback(self) -> int:
        """Minimum bars needed before output is valid."""
        pass

    @abstractmethod
    def calculate(self, *inputs: NDArray[np.float64]) -> T:
        """
        Pure calculation. No side effects.
        Returns array same length as first input, with NaN for insufficient lookback.
        """
        pass
