"""Plugin system for custom ORBIT analyzers."""

from __future__ import annotations

import importlib.util
import logging
import sys
from abc import ABC, abstractmethod
from dataclasses import dataclass
from pathlib import Path
from typing import Any

import numpy as np

logger = logging.getLogger(__name__)

DEFAULT_PLUGINS_DIR = Path.home() / ".orbit" / "plugins"


class BaseAnalyzer(ABC):
    """Base class for custom ORBIT analyzer plugins.

    Subclass this and place in ~/.orbit/plugins/ to add custom analysis
    dimensions to orbit analyze.

    Example:
        # ~/.orbit/plugins/gripper_wear.py
        from orbit.plugins import BaseAnalyzer, AnalyzerResult

        class GripperWearAnalyzer(BaseAnalyzer):
            name = "gripper_wear"
            description = "Detect gripper wear patterns in action data"

            def analyze(self, action_episodes, info=None, **kwargs):
                # Your custom analysis logic
                score = 0.85
                return AnalyzerResult(
                    name=self.name,
                    score=score,
                    status="ok" if score > 0.7 else "warn",
                    summary="Gripper actions look healthy",
                    details={"wear_index": 0.15},
                )
    """

    name: str = "unnamed"
    description: str = ""

    @abstractmethod
    def analyze(
        self,
        action_episodes: list[np.ndarray],
        info: Any = None,
        **kwargs,
    ) -> "AnalyzerResult":
        """Run the analysis. Must return an AnalyzerResult."""
        ...


@dataclass
class AnalyzerResult:
    """Result from a custom analyzer plugin."""

    name: str
    score: float  # 0.0 - 1.0
    status: str  # "ok", "warn", "bad"
    summary: str
    details: dict | None = None


def discover_plugins(plugins_dir: Path | None = None) -> list[type[BaseAnalyzer]]:
    """Discover and load analyzer plugins from the plugins directory."""
    dir_path = plugins_dir or DEFAULT_PLUGINS_DIR
    if not dir_path.exists():
        return []

    analyzers: list[type[BaseAnalyzer]] = []

    for py_file in sorted(dir_path.glob("*.py")):
        if py_file.name.startswith("_"):
            continue

        try:
            spec = importlib.util.spec_from_file_location(
                f"orbit_plugin_{py_file.stem}", py_file
            )
            if spec is None or spec.loader is None:
                continue
            module = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(module)

            # Find all BaseAnalyzer subclasses in the module
            for attr_name in dir(module):
                attr = getattr(module, attr_name)
                if (
                    isinstance(attr, type)
                    and issubclass(attr, BaseAnalyzer)
                    and attr is not BaseAnalyzer
                ):
                    analyzers.append(attr)
                    logger.debug(f"Loaded plugin: {attr.name} from {py_file.name}")

        except Exception as e:
            logger.warning(f"Failed to load plugin {py_file.name}: {e}")

    return analyzers


def run_plugins(
    action_episodes: list[np.ndarray],
    info: Any = None,
    plugins_dir: Path | None = None,
    **kwargs,
) -> list[AnalyzerResult]:
    """Discover and run all analyzer plugins, returning their results."""
    plugin_classes = discover_plugins(plugins_dir)
    results: list[AnalyzerResult] = []

    for cls in plugin_classes:
        try:
            analyzer = cls()
            result = analyzer.analyze(action_episodes, info=info, **kwargs)
            results.append(result)
        except Exception as e:
            logger.warning(f"Plugin {cls.name} failed: {e}")
            results.append(AnalyzerResult(
                name=cls.name,
                score=0.0,
                status="bad",
                summary=f"Plugin error: {e}",
            ))

    return results
