from abc import ABC, abstractmethod
import numpy as np
import pandas as pd
from typing import Dict, Any, Sequence

class SymbolicRegressionEngine(ABC):
    """
    Base class for symbolic regression engines
    """
    def __init__(self, backend_kwargs, wrapper_kwargs):
        self.backend_kwargs = backend_kwargs
        self.wrapper_kwargs = wrapper_kwargs
    
    @abstractmethod
    def fit(self, X: np.ndarray, y: np.ndarray) -> None:
        pass

    def fit_multi(self, Xs, ys):
        raise NotImplementedError(f"{self.__class__.__name__} doesn't support multi-SR. Please use a different engine.")

    @abstractmethod
    def get_expressions(self) -> pd.Series:
        pass

    @property
    @abstractmethod
    def engine_variable_names(self) -> Sequence[str]:
        """
        The variable names that this engine uses internally
        (in the generated expression strings), in the same order
        as the input features.
        """
        pass

    @classmethod
    def _default_backend_kwargs(cls):
        return {}

    def save(self, path: str) -> None:
        """
        Save this engine instance to disk via pickle.
        """
        import pickle
        with open(path, "wb") as f:
            pickle.dump(self, f)

    @classmethod
    def load(cls, path: str):
        """
        Load an engine instance from disk (pickle file).
        """
        import pickle
        with open(path, "rb") as f:
            obj = pickle.load(f)
        if not isinstance(obj, cls):
            raise TypeError(f"Loaded object is not a {cls.__name__}")
        return obj