"""Central LLM configuration for Hikaflow.

Reads environment variables to determine which LLM provider and base URL
to use. Supports DeepSeek, OpenAI, and Anthropic via a unified OpenAI-
compatible interface.

Environment variables (checked in order):
    HIKAFLOW_LLM_PROVIDER  - "deepseek", "openai", or "anthropic" (default: auto-detect)
    HIKAFLOW_LLM_BASE_URL  - Base URL for OpenAI-compatible API
    HIKAFLOW_LLM_API_KEY   - API key for the LLM provider
    DEEPSEEK_API_KEY        - DeepSeek-specific API key
    OPENAI_API_KEY          - OpenAI API key
    ANTHROPIC_API_KEY       - Anthropic API key
"""

from __future__ import annotations

import json
import os
import logging
from dataclasses import dataclass
from pathlib import Path
from typing import Optional

logger = logging.getLogger(__name__)

# DeepSeek model mapping
DEEPSEEK_MODELS = {
    "deepseek-chat": "deepseek-chat",        # DeepSeek V3.2
    "deepseek-reasoner": "deepseek-reasoner", # DeepSeek R1
}

# Default models per provider
DEFAULT_MODELS = {
    "deepseek": "deepseek-chat",
    "openai": "gpt-5",
    "anthropic": "claude-sonnet-4-20250514",
}

# Cost per 1K tokens (input/output) for tracking
MODEL_COSTS = {
    "deepseek-chat": (0.00028, 0.00042),
    "deepseek-reasoner": (0.00055, 0.00219),
    "gpt-5": (0.00125, 0.01000),
    "gpt-4o-mini": (0.00015, 0.00060),
    "claude-sonnet-4-20250514": (0.003, 0.015),
    "claude-haiku-4-5-20251001": (0.001, 0.005),
    # Qwen via OpenRouter ($0.18/M input, $0.54/M output for 235b)
    "qwen/qwen3-235b-a22b": (0.00018, 0.00054),
    "qwen/qwen3-30b-a3b": (0.00007, 0.00010),
    # Gemini Flash via OpenRouter ($0.15/M input, $0.60/M output)
    "google/gemini-2.5-flash": (0.00015, 0.00060),
}


@dataclass
class LLMConfig:
    """Resolved LLM configuration."""

    provider: str           # "deepseek", "openai", or "anthropic"
    api_key: str
    base_url: Optional[str]  # None for Anthropic (uses native SDK)
    default_model: str
    is_openai_compatible: bool  # True for deepseek/openai, False for anthropic

    def get_cost(self, model: Optional[str] = None) -> tuple[float, float]:
        """Get (input_cost, output_cost) per 1K tokens."""
        m = model or self.default_model
        return MODEL_COSTS.get(m, (0.001, 0.005))


def get_llm_config() -> LLMConfig:
    """Resolve LLM configuration from environment variables.

    Detection order:
    1. Explicit HIKAFLOW_LLM_PROVIDER
    2. DEEPSEEK_API_KEY present → deepseek
    3. HIKAFLOW_LLM_BASE_URL present → openai-compatible
    4. OPENAI_API_KEY present → openai
    5. ANTHROPIC_API_KEY present → anthropic
    """
    explicit_provider = os.environ.get("HIKAFLOW_LLM_PROVIDER", "").lower()
    base_url = os.environ.get("HIKAFLOW_LLM_BASE_URL")
    llm_api_key = os.environ.get("HIKAFLOW_LLM_API_KEY")
    deepseek_key = os.environ.get("DEEPSEEK_API_KEY")
    openai_key = os.environ.get("OPENAI_API_KEY")
    anthropic_key = os.environ.get("ANTHROPIC_API_KEY")

    if explicit_provider == "deepseek" or (not explicit_provider and deepseek_key):
        api_key = llm_api_key or deepseek_key or ""
        return LLMConfig(
            provider="deepseek",
            api_key=api_key,
            base_url=base_url or "https://api.deepseek.com",
            default_model="deepseek-chat",
            is_openai_compatible=True,
        )

    if explicit_provider == "openai" or (not explicit_provider and base_url):
        api_key = llm_api_key or openai_key or ""
        return LLMConfig(
            provider="openai",
            api_key=api_key,
            base_url=base_url,  # None = default openai
            default_model="gpt-5",
            is_openai_compatible=True,
        )

    if explicit_provider == "anthropic" or (not explicit_provider and anthropic_key):
        return LLMConfig(
            provider="anthropic",
            api_key=anthropic_key or "",
            base_url=None,
            default_model="claude-sonnet-4-20250514",
            is_openai_compatible=False,
        )

    # Check ~/.hikaflow/credentials.json for OpenRouter key
    openrouter_key = os.environ.get("OPENROUTER_API_KEY", "")
    if not openrouter_key:
        try:
            creds_path = Path.home() / ".hikaflow" / "credentials.json"
            if creds_path.exists():
                creds = json.loads(creds_path.read_text())
                openrouter_key = creds.get("openrouter_api_key", "")
        except Exception:
            pass

    if openrouter_key:
        return LLMConfig(
            provider="openrouter",
            api_key=openrouter_key,
            base_url="https://openrouter.ai/api/v1",
            default_model=os.getenv("HIKAFLOW_ORCHESTRATOR_MODEL", "qwen/qwen3-235b-a22b"),
            is_openai_compatible=True,
        )

    # Fallback: check for any available key
    if openai_key:
        return LLMConfig(
            provider="openai",
            api_key=openai_key,
            base_url=None,
            default_model="gpt-5",
            is_openai_compatible=True,
        )

    raise ValueError(
        "No LLM provider configured. Set one of: "
        "OPENROUTER_API_KEY, DEEPSEEK_API_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY"
    )


def create_openai_client(config: Optional[LLMConfig] = None):
    """Create an OpenAI SDK client pointing at the configured provider.

    Works for DeepSeek, OpenAI, or any OpenAI-compatible endpoint.
    """
    import openai

    if config is None:
        config = get_llm_config()

    kwargs = {"api_key": config.api_key}
    if config.base_url:
        kwargs["base_url"] = config.base_url
    return openai.OpenAI(**kwargs)


def create_async_openai_client(config: Optional[LLMConfig] = None):
    """Create an async OpenAI SDK client pointing at the configured provider."""
    import openai

    if config is None:
        config = get_llm_config()

    kwargs = {"api_key": config.api_key}
    if config.base_url:
        kwargs["base_url"] = config.base_url
    return openai.AsyncOpenAI(**kwargs)


def get_chat_model(config: Optional[LLMConfig] = None, model: Optional[str] = None):
    """Create a LangChain chat model for the configured provider.

    Returns ChatOpenAI for deepseek/openai, ChatAnthropic for anthropic.
    """
    if config is None:
        config = get_llm_config()

    model_name = model or config.default_model

    if config.is_openai_compatible:
        from langchain_openai import ChatOpenAI

        kwargs = {
            "model": model_name,
            "api_key": config.api_key,
            "max_tokens": 16384,
        }
        if config.base_url:
            kwargs["base_url"] = config.base_url
        return ChatOpenAI(**kwargs)
    else:
        from langchain_anthropic import ChatAnthropic

        return ChatAnthropic(
            model=model_name,
            max_tokens=16384,
            api_key=config.api_key,
        )


def get_embedding_base_url() -> Optional[str]:
    """Get base URL for embedding API calls.

    Embeddings stay on OpenAI unless explicitly overridden,
    since DeepSeek doesn't offer embeddings.
    """
    return os.environ.get("HIKAFLOW_EMBEDDING_BASE_URL")
