"""Base interfaces for NeuroWeave features."""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Any

import numpy as np


class BaseFeature(ABC):
    """Base class for all NeuroWeave feature steps.

    Parameters
    ----------
    name : str | None, optional
        Human-readable feature step name. Defaults to the lowercase class
        name when omitted.
    """

    def __init__(self, name: str | None = None) -> None:
        self.name = name or self.__class__.__name__.lower()
        self._feature_names: list[str] = []
        self._input_feature_names: list[str] = []

    def fit(self, X: np.ndarray) -> BaseFeature:
        """Fit the feature step.

        Parameters
        ----------
        X : np.ndarray
            Input stimulus or feature matrix.

        Returns
        -------
        BaseFeature
            The fitted feature step.
        """

        return self

    @abstractmethod
    def transform(self, X: np.ndarray) -> np.ndarray:
        """Transform an input array into feature outputs.

        Parameters
        ----------
        X : np.ndarray
            Input stimulus or feature matrix.

        Returns
        -------
        np.ndarray
            Transformed feature matrix.
        """

        raise NotImplementedError()

    def fit_transform(self, X: np.ndarray) -> np.ndarray:
        """Fit the step and transform the input.

        Parameters
        ----------
        X : np.ndarray
            Input stimulus or feature matrix.

        Returns
        -------
        np.ndarray
            Transformed feature matrix.
        """

        self.fit(X)
        return self.transform(X)

    @property
    def feature_names(self) -> list[str]:
        """Feature names associated with the most recent output."""

        return list(self._feature_names)

    @property
    def input_feature_names(self) -> list[str]:
        """Feature names provided by the previous pipeline step."""

        return list(self._input_feature_names)

    @property
    def metadata(self) -> dict[str, Any]:
        """Metadata describing the feature output."""

        return {"name": self.name, "feature_names": self.feature_names}
