"""Provider manager for handling AI providers."""

from __future__ import annotations

import os
import shutil
from typing import Any, Optional

import httpx

from ..types import ProviderInfo
from ..utils.config import load_config, save_config
from ..utils.logger import Logger
from .base_provider import BaseProvider
from .kimi_provider import KimiProvider
from .ollama_provider import OllamaProvider

# Optional providers - import with try/except
try:
    from .openai_provider import OpenAIProvider
except ImportError:
    OpenAIProvider = None  # type: ignore

try:
    from .anthropic_provider import AnthropicProvider
except ImportError:
    AnthropicProvider = None  # type: ignore

try:
    from .gemini_provider import GeminiProvider
except ImportError:
    GeminiProvider = None  # type: ignore

# Environment variable names for each provider
ENV_VARS: dict[str, list[str]] = {
    "OpenAI": ["OPENAI_API_KEY"],
    "Gemini": ["GEMINI_API_KEY", "GOOGLE_API_KEY"],
    "Anthropic": ["ANTHROPIC_API_KEY"],
    "OpenRouter": ["OPENROUTER_API_KEY"],
    "Groq": ["GROQ_API_KEY"],
    "Cohere": ["COHERE_API_KEY"],
}


class ProviderManager:
    """Manages AI providers and their configuration."""

    def __init__(self) -> None:
        self.current_provider: Optional[BaseProvider] = None

    def has_configured_provider(self) -> bool:
        """Check if a provider is configured."""
        try:
            config = load_config()
            return config.provider is not None
        except Exception:
            return False

    def reload_from_disk(self) -> None:
        """Reload provider from config."""
        config = load_config()
        if config.provider:
            self.set_provider(config.provider["name"], config.provider)

    def detect_all_providers(self) -> list[ProviderInfo]:
        """Detect all available providers."""
        Logger.info("Detecting all available providers")

        providers: list[ProviderInfo] = [
            # CLI-based providers
            ProviderInfo(name="Kimi Code CLI", type="cli", available=False),
            ProviderInfo(name="Claude CLI", type="cli", available=False),
            ProviderInfo(name="OpenAI Codex CLI", type="cli", available=False),
            # Local providers
            ProviderInfo(name="Ollama (Local)", type="api", available=False),
            # Cloud API providers
            ProviderInfo(name="OpenAI", type="api", available=False, api_key_source="env"),
            ProviderInfo(name="Gemini", type="api", available=False, api_key_source="env"),
            ProviderInfo(name="Anthropic", type="api", available=False, api_key_source="env"),
            ProviderInfo(name="OpenRouter", type="api", available=False, api_key_source="env"),
            ProviderInfo(name="Groq", type="api", available=False, api_key_source="env"),
            ProviderInfo(name="Cohere", type="api", available=False, api_key_source="env"),
        ]

        # Check CLI providers
        cli_map = {"Kimi Code CLI": "kimi-cli", "Claude CLI": "claude", "OpenAI Codex CLI": "codex"}

        for p in providers:
            if p.type == "cli":
                cli_name = cli_map.get(p.name)
                if cli_name:
                    path = shutil.which(cli_name)
                    if path:
                        p.available = True
                        p.path = path
                        # Get version
                        try:
                            import subprocess

                            result = subprocess.run(
                                [cli_name, "--version"], capture_output=True, text=True, timeout=5
                            )
                            if result.returncode == 0:
                                p.version = result.stdout.strip()
                        except Exception:
                            pass

        # Check local Ollama
        ollama = next((p for p in providers if p.name == "Ollama (Local)"), None)
        if ollama:
            try:
                response = httpx.get("http://localhost:11434/api/tags", timeout=5.0)
                if response.status_code == 200:
                    ollama.available = True
                    data = response.json()
                    models = data.get("models", [])
                    if models:
                        ollama.model = f"{len(models)} models available"
            except Exception:
                ollama.available = False

        # Check API providers from environment
        for p in providers:
            if p.type == "api" and p.name in ENV_VARS:
                env_vars = ENV_VARS[p.name]
                for env_var in env_vars:
                    if os.environ.get(env_var):
                        p.available = True
                        p.api_key_source = f"env:{env_var}"
                        break

        # Sort: available first, then by type
        providers.sort(
            key=lambda p: (
                not p.available,
                p.type == "api",  # CLI before API
            )
        )

        return providers

    def set_provider(self, name: str, config: Optional[dict] = None) -> None:
        """Set the current provider."""
        Logger.info("Setting provider", {"name": name, "config": config})

        config = config or {}
        provider: BaseProvider

        if name == "Kimi Code CLI":
            provider = KimiProvider(model=config.get("model", "kimi-code/kimi-for-coding"))

        elif name == "OpenAI":
            if OpenAIProvider is None:
                raise ValueError("OpenAI provider not available. Install with: pip install openai")
            api_key = config.get("apiKey") or os.environ.get("OPENAI_API_KEY")
            if not api_key:
                raise ValueError("OpenAI requires OPENAI_API_KEY")
            provider = OpenAIProvider(api_key, config.get("model", "gpt-4o"))

        elif name == "Gemini":
            if GeminiProvider is None:
                raise ValueError(
                    "Gemini provider not available. Install with: pip install google-generativeai"
                )
            api_key = (
                config.get("apiKey")
                or os.environ.get("GEMINI_API_KEY")
                or os.environ.get("GOOGLE_API_KEY")
            )
            if not api_key:
                raise ValueError("Gemini requires GEMINI_API_KEY or GOOGLE_API_KEY")
            provider = GeminiProvider(api_key, config.get("model", "gemini-pro"))

        elif name == "Anthropic":
            if AnthropicProvider is None:
                raise ValueError(
                    "Anthropic provider not available. Install with: pip install anthropic"
                )
            api_key = config.get("apiKey") or os.environ.get("ANTHROPIC_API_KEY")
            if not api_key:
                raise ValueError("Anthropic requires ANTHROPIC_API_KEY")
            provider = AnthropicProvider(api_key, config.get("model", "claude-3-5-sonnet-20241022"))

        elif name == "Ollama (Local)":
            provider = OllamaProvider(
                config.get("baseUrl", "http://localhost:11434"), config.get("model", "llama2")
            )

        else:
            raise ValueError(f"Unknown provider: {name}")

        # Test connection
        if not provider.test_connection():
            raise RuntimeError(f"Failed to connect to {name}. Please check your configuration.")

        self.current_provider = provider

        # Save config
        app_config = load_config()
        app_config.provider = {
            "name": name,
            "type": self._get_provider_type(name),
            **{k: v for k, v in config.items() if v is not None},
        }
        save_config(app_config)

    def _get_provider_type(self, name: str) -> str:
        """Get provider type."""
        cli_providers = ["Kimi Code CLI", "Claude CLI", "OpenAI Codex CLI"]
        return "cli" if name in cli_providers else "api"

    def execute(self, skill_content: str, user_input: str, context: dict[str, Any]) -> str:
        """Execute task with current provider."""
        if not self.current_provider:
            # Try to load from config
            config = load_config()
            if config.provider:
                self.set_provider(config.provider["name"], config.provider)
            else:
                raise RuntimeError("No provider configured")

        return self.current_provider.execute(skill_content, user_input, context)

    def get_current_provider(self) -> Optional[BaseProvider]:
        """Get current provider."""
        return self.current_provider

    def get_current_provider_name(self) -> Optional[str]:
        """Get current provider name."""
        return self.current_provider.name if self.current_provider else None

    def get_available_models(
        self, provider_name: str, api_key: Optional[str] = None, base_url: Optional[str] = None
    ) -> list[dict]:
        """Get available models for provider."""
        if provider_name == "Anthropic":
            if AnthropicProvider is None:
                return []
            if not api_key:
                return [
                    {
                        "id": "claude-3-5-sonnet-20241022",
                        "name": "Claude 3.5 Sonnet",
                        "description": "Most capable",
                    },
                    {
                        "id": "claude-3-opus-20240229",
                        "name": "Claude 3 Opus",
                        "description": "Powerful",
                    },
                ]
            return AnthropicProvider.get_available_models(api_key)

        elif provider_name == "OpenAI":
            return [
                {"id": "gpt-4o", "name": "GPT-4o", "description": "Most capable"},
                {"id": "gpt-4-turbo", "name": "GPT-4 Turbo", "description": "Fast and capable"},
                {
                    "id": "gpt-3.5-turbo",
                    "name": "GPT-3.5 Turbo",
                    "description": "Fast and affordable",
                },
            ]

        elif provider_name == "Gemini":
            return [
                {"id": "gemini-pro", "name": "Gemini Pro", "description": "For most tasks"},
                {"id": "gemini-ultra", "name": "Gemini Ultra", "description": "Most capable"},
            ]

        elif provider_name == "Ollama (Local)":
            if base_url:
                ollama = OllamaProvider(base_url)
                models = ollama.list_models()
                return [{"id": m, "name": m} for m in models]
            return []

        return []
