"""
Base class for instrumentors.

Instrumentors provide automatic metric collection and tracing for specific libraries.
They follow a plugin architecture where each instrumentor self-registers with the
InstrumentorRegistry.
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Dict, Optional


@dataclass
class MetricSchema:
    """
    Describes a metric that an instrumentor may log.

    This is used for documentation/discovery, NOT validation.
    The schema-less design means any metric can be logged,
    but MetricSchema helps developers understand what metrics
    are available from each instrumentor.
    """

    name: str
    description: str
    unit: str = ""
    metric_type: str = "gauge"  # gauge, counter, histogram
    labels: Dict[str, str] = field(default_factory=dict)  # Label name -> description


class Instrumentor(ABC):
    """
    Base class for auto-instrumentation plugins.

    Instrumentors provide automatic metric collection and tracing
    for specific libraries (e.g., OpenAI, Anthropic, custom algorithms).

    Usage:
        class OpenAIInstrumentor(Instrumentor):
            @property
            def name(self) -> str:
                return "openai"

            def instrument(self) -> None:
                # Apply monkey patches or hooks
                pass

            def uninstrument(self) -> None:
                # Remove patches
                pass

    Instrumentors are registered via the InstrumentorRegistry:
        InstrumentorRegistry.register("openai", OpenAIInstrumentor)

    Or via Python entry points in pyproject.toml:
        [project.entry-points."mantisdk.instrumentors"]
        openai = "mantisdk.instrumentation.openai:OpenAIInstrumentor"
    """

    @property
    @abstractmethod
    def name(self) -> str:
        """
        Unique identifier for this instrumentor.

        Examples: 'openai', 'anthropic', 'gepa', 'langchain'
        """
        pass

    @property
    def default_labels(self) -> Dict[str, str]:
        """
        Labels added to all metrics from this instrumentor.

        Override to add custom default labels. By default,
        includes the instrumentor name.
        """
        return {"instrumentor": self.name}

    def get_metric_schema(self) -> Dict[str, MetricSchema]:
        """
        Describe metrics this instrumentor may log.

        Used for documentation/discovery, NOT validation.
        Returns a dict mapping metric names to their schemas.

        Override this to document the metrics your instrumentor logs.
        """
        return {}

    @abstractmethod
    def instrument(self) -> None:
        """
        Apply patches/hooks to the target library.

        This method is called when the instrumentor is activated.
        It should apply any necessary monkey patches, register
        callbacks, or otherwise hook into the target library.
        """
        pass

    def uninstrument(self) -> None:
        """
        Remove patches/hooks from the target library.

        Override this method to provide cleanup functionality.
        Used primarily for testing to restore original behavior.
        """
        pass

    def is_available(self) -> bool:
        """
        Check if the target library is available.

        Override this to check if the library this instrumentor
        targets is installed. By default returns True.
        """
        return True
