from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional
import numpy as np
import torch


class BaseEvaluator(ABC):
    """
    Abstract base class defining the interface for all evaluators.

    Evaluators can be either ML-based (using trained models) or physics-based
    (using computational methods like PyRosetta).
    """

    def __init__(self, name: str, task_type: str, **kwargs):
        """
        Initialize the evaluator.

        Args:
            name: Name of the evaluator
            task_type: Type of task ('filter', 'score', or 'seq_prob')
            **kwargs: Additional configuration parameters
        """
        self.name = name
        self.task_type = task_type
        self.config = kwargs

    @abstractmethod
    def predict(self, sequences: List[str], batch_size: int = 1) -> Dict[str, Any]:
        """
        Make predictions on a list of sequences.

        Args:
            sequences: List of protein sequences to evaluate
            batch_size: Optional batch size for processing (for ML models)

        Returns:
            Dict[str, Any]: Predictions for each sequence e.g. {"predictions": np.ndarray, "probabilities": np.ndarray}
        """
        pass

    @abstractmethod
    def setup(self, **kwargs) -> None:
        """
        Set up the evaluator with any required resources.

        Args:
            **kwargs: Configuration parameters for setup
        """
        pass

    def __str__(self) -> str:
        return (
            f"{self.__class__.__name__}(name={self.name}, task_type={self.task_type})"
        )

    def __repr__(self) -> str:
        return self.__str__()
