"""Vision analysis resource for CMDOP LLM service."""

from __future__ import annotations

from typing import TYPE_CHECKING, Literal, Optional, Union

import httpx
from openai._compat import cached_property
from openai._resource import AsyncAPIResource, SyncAPIResource
from openai._types import NOT_GIVEN, Body, Headers, NotGiven, Query

from ..types.vision import VisionAnalyzeResponse

if TYPE_CHECKING:
    from .._client import AsyncCmdopLLM, CmdopLLM

__all__ = ["Vision", "AsyncVision"]


class Vision(SyncAPIResource):
    """Vision analysis resource.

    Provides image analysis capabilities using vision models.

    Example:
        ```python
        from cmdop_llm import CmdopLLM

        client = CmdopLLM()
        result = client.vision.analyze(
            image_url="https://example.com/image.jpg",
            prompt="Describe this image"
        )
        print(result.description)
        ```
    """

    _client: CmdopLLM

    @cached_property
    def with_raw_response(self) -> VisionWithRawResponse:
        """Access raw HTTP response data."""
        return VisionWithRawResponse(self)

    def analyze(
        self,
        *,
        image: Optional[str] = None,
        image_url: Optional[str] = None,
        prompt: Optional[str] = None,
        model: Optional[str] = None,
        ocr_mode: Literal["tiny", "small", "base", "gundam"] = "base",
        fetch_image: bool = True,
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: Union[float, httpx.Timeout, None, NotGiven] = NOT_GIVEN,
    ) -> VisionAnalyzeResponse:
        """Analyze an image using a vision model.

        Args:
            image: Base64-encoded image data.
            image_url: URL of the image to analyze.
            prompt: Custom prompt for the analysis.
            model: Model to use. Defaults to server default.
            ocr_mode: OCR quality mode ("tiny", "small", "base", "gundam").
            fetch_image: Whether server should fetch image from URL.
            extra_headers: Additional headers to send.
            extra_query: Additional query parameters.
            extra_body: Additional body parameters.
            timeout: Request timeout.

        Returns:
            VisionAnalyzeResponse with extracted text and description.

        Raises:
            ValueError: If neither image nor image_url is provided.
            openai.APIError: If the request fails.
        """
        if not image and not image_url:
            raise ValueError("Either 'image' or 'image_url' must be provided")

        body = {
            "image": image,
            "image_url": image_url,
            "prompt": prompt,
            "model": model,
            "ocr_mode": ocr_mode,
            "fetch_image": fetch_image,
        }
        # Remove None values
        body = {k: v for k, v in body.items() if v is not None}

        return self._post(
            "/vision/analyze",
            body=body,
            options={
                "extra_headers": extra_headers,
                "extra_query": extra_query,
                "extra_body": extra_body,
                "timeout": timeout,
            },
            cast_to=VisionAnalyzeResponse,
        )


class AsyncVision(AsyncAPIResource):
    """Async vision analysis resource."""

    _client: AsyncCmdopLLM

    @cached_property
    def with_raw_response(self) -> AsyncVisionWithRawResponse:
        """Access raw HTTP response data."""
        return AsyncVisionWithRawResponse(self)

    async def analyze(
        self,
        *,
        image: Optional[str] = None,
        image_url: Optional[str] = None,
        prompt: Optional[str] = None,
        model: Optional[str] = None,
        ocr_mode: Literal["tiny", "small", "base", "gundam"] = "base",
        fetch_image: bool = True,
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: Union[float, httpx.Timeout, None, NotGiven] = NOT_GIVEN,
    ) -> VisionAnalyzeResponse:
        """Analyze an image using a vision model (async).

        See Vision.analyze for full documentation.
        """
        if not image and not image_url:
            raise ValueError("Either 'image' or 'image_url' must be provided")

        body = {
            "image": image,
            "image_url": image_url,
            "prompt": prompt,
            "model": model,
            "ocr_mode": ocr_mode,
            "fetch_image": fetch_image,
        }
        body = {k: v for k, v in body.items() if v is not None}

        return await self._post(
            "/vision/analyze",
            body=body,
            options={
                "extra_headers": extra_headers,
                "extra_query": extra_query,
                "extra_body": extra_body,
                "timeout": timeout,
            },
            cast_to=VisionAnalyzeResponse,
        )


class VisionWithRawResponse:
    """Raw response wrapper for Vision resource."""

    def __init__(self, vision: Vision) -> None:
        self._vision = vision

    def analyze(self, **kwargs) -> httpx.Response:  # type: ignore
        """Get raw response from analyze."""
        return self._vision._client.with_raw_response._post(  # type: ignore
            "/vision/analyze",
            body=kwargs,
        )


class AsyncVisionWithRawResponse:
    """Raw response wrapper for AsyncVision resource."""

    def __init__(self, vision: AsyncVision) -> None:
        self._vision = vision

    async def analyze(self, **kwargs) -> httpx.Response:  # type: ignore
        """Get raw response from analyze."""
        return await self._vision._client.with_raw_response._post(  # type: ignore
            "/vision/analyze",
            body=kwargs,
        )
