"""Sync SDKRouter client."""

from __future__ import annotations

import logging
from typing import Any, Optional, Type, cast

from openai import OpenAI

from .._config import SDKConfig
from .._constants import DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT
from .._types.parsed import ParsedChatCompletion
from ..utils.parsing import ResponseFormatT, type_to_response_format

from ._base import resolve_init_params
from ._helpers import LazyTool, merge_provider_extra_body, parse_completion

# Sync tool imports
from ..tools.vision import VisionResource
from ..tools.cdn import CDNResource
from ..tools.shortlinks import ShortlinksResource
from ..tools.keys import KeysResource
from ..tools.cleaner import CleanerResource
from ..tools.models import ModelsResource
from ..tools.research import ResearchResource
from ..tools.embeddings import EmbeddingsResource
from ..tools.image_gen import ImageGenResource
from ..tools.audio import AudioResource
from ..tools.payments import PaymentsResource
from ..tools.proxies import ProxiesResource
from ..tools.translator import TranslatorResource
from ..tools.knowbase import KnowledgeBaseResource
from ..tools.banner import BannerResource
from ..tools.crawler import CrawlerResource
from ..tools.email import EmailResource
from ..tools.telegram import TelegramResource

logger = logging.getLogger(__name__)


class SDKRouter(OpenAI):
    """Sync SDK client — OpenAI-compatible with additional tools.

    Example:
        ```python
        from sdkrouter import SDKRouter

        client = SDKRouter(api_key="sk_live_...")
        response = client.chat.completions.create(
            model="openai/gpt-4o",
            messages=[{"role": "user", "content": "Hello!"}],
        )
        ```
    """

    # ── Tool properties (lazy-loaded via descriptor) ─────────────────────
    vision = LazyTool("_vision", VisionResource, "Vision analysis and OCR")
    cdn = LazyTool("_cdn", CDNResource, "CDN file storage")
    shortlinks = LazyTool("_shortlinks", ShortlinksResource, "URL shortening")
    keys = LazyTool("_keys", KeysResource, "API keys management")
    cleaner = LazyTool("_api_cleaner", CleanerResource, "HTML cleaner (server-side)")
    llm_models = LazyTool("_models", ModelsResource, "LLM models listing")
    research = LazyTool("_search", ResearchResource, "Web research")
    image_gen = LazyTool("_image_gen", ImageGenResource, "AI image generation")
    payments = LazyTool("_payments", PaymentsResource, "Crypto payments")
    proxies = LazyTool("_proxies", ProxiesResource, "Proxy management")
    translator = LazyTool("_translator", TranslatorResource, "JSON/text translation")
    knowbase = LazyTool("_knowbase", KnowledgeBaseResource, "Knowledge base")
    banner = LazyTool("_banner", BannerResource, "Banner generator")
    crawler = LazyTool("_crawler", CrawlerResource, "Web scraping")
    email = LazyTool("_email", EmailResource, "Email gateway")
    telegram = LazyTool("_telegram", TelegramResource, "Telegram bots + MTProto")

    def __init__(
        self,
        *,
        api_key: Optional[str] = None,
        llm_url: Optional[str] = None,
        api_url: Optional[str] = None,
        audio_url: Optional[str] = None,
        dev: bool = False,
        use_self_hosted: bool = True,
        openrouter_api_key: Optional[str] = None,
        provider: Optional[str] = None,
        timeout: float = DEFAULT_TIMEOUT,
        max_retries: int = DEFAULT_MAX_RETRIES,
        **kwargs,
    ):
        """Initialize SDKRouter.

        Args:
            api_key: SDK API key (or set SDKROUTER_API_KEY env var)
            dev: Use localhost URLs for all services
            llm_url: Override LLM URL
            api_url: Override Django API URL
            audio_url: Override Audio URL
            use_self_hosted: Route through self-hosted proxy (default True)
            provider: Default provider hint
            timeout: Request timeout in seconds
            max_retries: Retry count
        """
        resolved_key, openai_base_url, _, _, config = resolve_init_params(
            api_key=api_key, llm_url=llm_url, api_url=api_url, audio_url=audio_url,
            dev=dev, use_self_hosted=use_self_hosted,
            openrouter_api_key=openrouter_api_key, provider=provider,
            timeout=timeout, max_retries=max_retries,
        )

        kwargs.pop("base_url", None)
        super().__init__(
            api_key=resolved_key,
            base_url=openai_base_url,
            timeout=timeout,
            max_retries=max_retries,
            **kwargs,
        )

        self._provider = provider
        self._sdk_config = config

    # ── Special tools (need provider injection) ──────────────────────────

    @property
    def embeddings(self) -> EmbeddingsResource:  # type: ignore[override]
        """Embeddings tool."""
        if not hasattr(self, "_embeddings") or self._embeddings is None:
            self._embeddings = EmbeddingsResource(self._sdk_config)
            self._embeddings._provider = self._provider
        return self._embeddings

    @property
    def audio(self) -> AudioResource:  # type: ignore[override]
        """Audio (STT/TTS) tool."""
        if not hasattr(self, "_audio") or self._audio is None:
            self._audio = AudioResource(self._sdk_config)
        return self._audio

    @property
    def config(self) -> SDKConfig:
        return self._sdk_config

    # ── Structured output ────────────────────────────────────────────────

    def parse(
        self,
        *,
        model: str,
        messages: list[dict[str, Any]],
        response_format: Type[ResponseFormatT],
        temperature: Optional[float] = None,
        max_tokens: Optional[int] = None,
        top_p: Optional[float] = None,
        frequency_penalty: Optional[float] = None,
        presence_penalty: Optional[float] = None,
        stop: Optional[list[str]] = None,
        seed: Optional[int] = None,
        **kwargs: Any,
    ) -> ParsedChatCompletion[ResponseFormatT]:
        """Chat completion with structured output (Pydantic model parsing)."""
        format_param = type_to_response_format(response_format)
        params = _build_parse_params(
            model, messages, format_param,
            temperature, max_tokens, top_p,
            frequency_penalty, presence_penalty, stop, seed,
            **kwargs,
        )
        merge_provider_extra_body(self._provider, params)
        raw = self.chat.completions.create(**params)
        return parse_completion(raw, response_format)


def _build_parse_params(
    model, messages, format_param,
    temperature, max_tokens, top_p,
    frequency_penalty, presence_penalty, stop, seed,
    **kwargs,
) -> dict[str, Any]:
    """Build params dict for parse(), filtering None values."""
    params: dict[str, Any] = {
        "model": model,
        "messages": cast(Any, messages),
        "response_format": cast(Any, format_param),
    }
    for key, val in [
        ("temperature", temperature), ("max_tokens", max_tokens),
        ("top_p", top_p), ("frequency_penalty", frequency_penalty),
        ("presence_penalty", presence_penalty), ("stop", stop), ("seed", seed),
    ]:
        if val is not None:
            params[key] = val
    params.update(kwargs)
    return params
