"""
Auto-instrument engine — detects installed AI provider packages and patches them.

Usage:
    syn = Syntropy.init(api_key="syn_...", agent_id="my-agent")
    # That's it — OpenAI, Anthropic, Mistral, etc. are auto-patched.

Alternatively, call instrument() directly:
    from syntropy.instrument import instrument
    instrument(syntropy_instance)
"""

from __future__ import annotations

import importlib
import importlib.util
import logging
from typing import Any, List

from syntropy.client import Syntropy

logger = logging.getLogger("syntropy")


def _is_installed(module_name: str) -> bool:
    """Check if a Python package is importable without actually importing it."""
    return importlib.util.find_spec(module_name) is not None


def instrument(syntropy: Syntropy) -> List[str]:
    """
    Auto-detect installed AI provider packages and monkey-patch them.

    Returns a list of provider names that were successfully patched.
    """
    patched: List[str] = []

    # ---- OpenAI ----
    if _is_installed("openai"):
        try:
            import openai  # type: ignore[import-not-found]
            from syntropy.integrations.openai import _TracedCompletions

            original_init = openai.OpenAI.__init__

            def _patched_openai_init(self: Any, *args: Any, **kwargs: Any) -> None:
                original_init(self, *args, **kwargs)
                self.chat.completions = _TracedCompletions(
                    self.chat.completions,
                    syntropy,
                    syntropy._config.agent_id,
                )

            openai.OpenAI.__init__ = _patched_openai_init  # type: ignore
            patched.append("openai")
            logger.info("Syntropy: auto-patched openai.OpenAI")
        except Exception as e:
            logger.debug("Syntropy: failed to patch openai: %s", e)

    # ---- Anthropic ----
    if _is_installed("anthropic"):
        try:
            import anthropic  # type: ignore[import-not-found]
            from syntropy.integrations.anthropic import _TracedMessages

            original_init = anthropic.Anthropic.__init__

            def _patched_anthropic_init(self: Any, *args: Any, **kwargs: Any) -> None:
                original_init(self, *args, **kwargs)
                self.messages = _TracedMessages(
                    self.messages,
                    syntropy,
                    syntropy._config.agent_id,
                )

            anthropic.Anthropic.__init__ = _patched_anthropic_init  # type: ignore
            patched.append("anthropic")
            logger.info("Syntropy: auto-patched anthropic.Anthropic")
        except Exception as e:
            logger.debug("Syntropy: failed to patch anthropic: %s", e)

    # ---- Mistral ----
    if _is_installed("mistralai"):
        try:
            import mistralai  # type: ignore[import-not-found]
            from syntropy.integrations.mistral import _TracedChatComplete

            original_init = mistralai.Mistral.__init__

            def _patched_mistral_init(self: Any, *args: Any, **kwargs: Any) -> None:
                original_init(self, *args, **kwargs)
                if hasattr(self, "chat"):
                    self.chat = _TracedChatComplete(
                        self.chat,
                        syntropy,
                        syntropy._config.agent_id,
                    )

            mistralai.Mistral.__init__ = _patched_mistral_init  # type: ignore
            patched.append("mistral")
            logger.info("Syntropy: auto-patched mistralai.Mistral")
        except Exception as e:
            logger.debug("Syntropy: failed to patch mistral: %s", e)

    # ---- Google Generative AI ----
    if _is_installed("google.generativeai"):
        try:
            import google.generativeai as genai  # type: ignore[import-not-found]
            from syntropy.integrations.google import TracedGenerativeModel

            original_init = genai.GenerativeModel.__init__

            def _patched_google_init(self: Any, *args: Any, **kwargs: Any) -> None:
                original_init(self, *args, **kwargs)
                # Wrap generate_content at instance level
                original_generate = self.generate_content

                def traced_generate(contents: Any, **kw: Any) -> Any:
                    wrapper = TracedGenerativeModel(self, syntropy, syntropy._config.agent_id)
                    wrapper._model.generate_content = original_generate
                    return wrapper.generate_content(contents, **kw)

                self.generate_content = traced_generate

            genai.GenerativeModel.__init__ = _patched_google_init  # type: ignore
            patched.append("google")
            logger.info("Syntropy: auto-patched google.generativeai.GenerativeModel")
        except Exception as e:
            logger.debug("Syntropy: failed to patch google: %s", e)

    if patched:
        logger.info("Syntropy: auto-instrumented providers: %s", ", ".join(patched))
    else:
        logger.info("Syntropy: no provider packages detected for auto-instrumentation")

    return patched
