"""Main client classes for CMDOP LLM service."""

from __future__ import annotations

import os
from typing import Mapping, Optional, Union

import httpx
from openai import AsyncOpenAI, OpenAI
from openai._compat import cached_property
from openai._types import NOT_GIVEN, NotGiven, Timeout

from ._constants import DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, ENV_API_KEY, ENV_BASE_URL
from .resources.ocr import AsyncOCR, OCR
from .resources.search import AsyncSearch, Search
from .resources.vision import AsyncVision, Vision

__all__ = ["CmdopLLM", "AsyncCmdopLLM"]


class CmdopLLM(OpenAI):
    """Synchronous client for CMDOP LLM service.

    A drop-in replacement for OpenAI client that connects to llm.cmdop.com.
    Provides access to 200+ AI models via OpenRouter, plus custom vision/OCR endpoints.

    Example:
        ```python
        from cmdop_llm import CmdopLLM

        # Initialize with API key
        client = CmdopLLM(api_key="your-cmdop-api-key")

        # Or use CMDOP_API_KEY environment variable
        client = CmdopLLM()

        # Chat completion (same as OpenAI)
        response = client.chat.completions.create(
            model="anthropic/claude-3.5-sonnet",
            messages=[{"role": "user", "content": "Hello!"}]
        )
        print(response.choices[0].message.content)

        # Vision analysis (CMDOP-specific)
        result = client.vision.analyze(
            image_url="https://example.com/image.jpg"
        )
        print(result.description)

        # OCR text extraction (CMDOP-specific)
        result = client.ocr.extract(
            image_url="https://example.com/document.png"
        )
        print(result.text)
        ```

    Args:
        api_key: CMDOP API key. If not provided, reads from CMDOP_API_KEY env var.
        base_url: Override the default base URL (https://llm.cmdop.com).
        timeout: Request timeout in seconds or httpx.Timeout object.
        max_retries: Maximum number of retries for failed requests.
        default_headers: Headers to include in all requests.
        default_query: Query parameters to include in all requests.
        http_client: Custom httpx.Client instance.
    """

    def __init__(
        self,
        *,
        api_key: Optional[str] = None,
        base_url: Union[str, httpx.URL, None] = None,
        timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
        max_retries: int = DEFAULT_MAX_RETRIES,
        default_headers: Optional[Mapping[str, str]] = None,
        default_query: Optional[Mapping[str, object]] = None,
        http_client: Optional[httpx.Client] = None,
    ) -> None:
        # Get API key from environment if not provided
        if api_key is None:
            api_key = os.environ.get(ENV_API_KEY)
            if api_key is None:
                raise ValueError(
                    f"API key is required. Set {ENV_API_KEY} environment variable "
                    "or pass api_key parameter."
                )

        # Get base URL from environment or use default
        if base_url is None:
            base_url = os.environ.get(ENV_BASE_URL, DEFAULT_BASE_URL)

        super().__init__(
            api_key=api_key,
            base_url=base_url,
            timeout=timeout,
            max_retries=max_retries,
            default_headers=default_headers,
            default_query=default_query,
            http_client=http_client,
        )

    @cached_property
    def vision(self) -> Vision:
        """Access vision analysis endpoints.

        Returns:
            Vision resource for image analysis.
        """
        return Vision(self)

    @cached_property
    def ocr(self) -> OCR:
        """Access OCR text extraction endpoints.

        Returns:
            OCR resource for text extraction from images.
        """
        return OCR(self)

    @cached_property
    def search(self) -> Search:
        """Access web search endpoints.

        Returns:
            Search resource for web search and URL fetching.
        """
        return Search(self)


class AsyncCmdopLLM(AsyncOpenAI):
    """Asynchronous client for CMDOP LLM service.

    Async version of CmdopLLM for use with asyncio.

    Example:
        ```python
        import asyncio
        from cmdop_llm import AsyncCmdopLLM

        async def main():
            client = AsyncCmdopLLM()

            # Chat completion
            response = await client.chat.completions.create(
                model="openai/gpt-4o",
                messages=[{"role": "user", "content": "Hello!"}]
            )
            print(response.choices[0].message.content)

            # Streaming
            stream = await client.chat.completions.create(
                model="openai/gpt-4o",
                messages=[{"role": "user", "content": "Write a poem"}],
                stream=True
            )
            async for chunk in stream:
                if chunk.choices[0].delta.content:
                    print(chunk.choices[0].delta.content, end="")

        asyncio.run(main())
        ```

    Args:
        api_key: CMDOP API key. If not provided, reads from CMDOP_API_KEY env var.
        base_url: Override the default base URL (https://llm.cmdop.com).
        timeout: Request timeout in seconds or httpx.Timeout object.
        max_retries: Maximum number of retries for failed requests.
        default_headers: Headers to include in all requests.
        default_query: Query parameters to include in all requests.
        http_client: Custom httpx.AsyncClient instance.
    """

    def __init__(
        self,
        *,
        api_key: Optional[str] = None,
        base_url: Union[str, httpx.URL, None] = None,
        timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
        max_retries: int = DEFAULT_MAX_RETRIES,
        default_headers: Optional[Mapping[str, str]] = None,
        default_query: Optional[Mapping[str, object]] = None,
        http_client: Optional[httpx.AsyncClient] = None,
    ) -> None:
        # Get API key from environment if not provided
        if api_key is None:
            api_key = os.environ.get(ENV_API_KEY)
            if api_key is None:
                raise ValueError(
                    f"API key is required. Set {ENV_API_KEY} environment variable "
                    "or pass api_key parameter."
                )

        # Get base URL from environment or use default
        if base_url is None:
            base_url = os.environ.get(ENV_BASE_URL, DEFAULT_BASE_URL)

        super().__init__(
            api_key=api_key,
            base_url=base_url,
            timeout=timeout,
            max_retries=max_retries,
            default_headers=default_headers,
            default_query=default_query,
            http_client=http_client,
        )

    @cached_property
    def vision(self) -> AsyncVision:
        """Access vision analysis endpoints.

        Returns:
            AsyncVision resource for image analysis.
        """
        return AsyncVision(self)

    @cached_property
    def ocr(self) -> AsyncOCR:
        """Access OCR text extraction endpoints.

        Returns:
            AsyncOCR resource for text extraction from images.
        """
        return AsyncOCR(self)

    @cached_property
    def search(self) -> AsyncSearch:
        """Access web search endpoints.

        Returns:
            AsyncSearch resource for web search and URL fetching.
        """
        return AsyncSearch(self)


# Aliases for convenience
Client = CmdopLLM
AsyncClient = AsyncCmdopLLM
