"""OpenAI adapter using official OpenAI SDK."""

import mimetypes
import base64
from pathlib import Path
from typing import List, Optional

from openai import OpenAI

from .base import VendorAdapter
from ..models import Response, Usage


class OpenAIAdapter(VendorAdapter):
    """
    OpenAI adapter using official OpenAI SDK.

    Supports:
    - Native file processing via Files API (for assistants, fine-tuning)
    - Vision models with base64 images
    - Custom base_url for proxies/relays
    """

    # Default endpoint and model
    DEFAULT_BASE_URL = "https://api.openai.com/v1"
    DEFAULT_MODEL = "gpt-4o"

    # Valid purposes for file upload
    VALID_PURPOSES = {"assistants", "fine-tune", "batch", "vision"}

    def __init__(
        self,
        api_key: str,
        model: Optional[str] = None,
        base_url: Optional[str] = None,
        timeout: Optional[float] = None,
        upload_purpose: str = "assistants",
        **kwargs
    ):
        """
        Initialize OpenAI adapter.

        Args:
            api_key: OpenAI API key.
            model: Model name. Defaults to gpt-4o.
            base_url: Custom API endpoint (for proxies/relays).
            timeout: Request timeout in seconds.
            upload_purpose: Purpose for file uploads via upload_file().
                           Valid: "assistants", "fine-tune", "batch", "vision".
                           Default: "assistants".
            **kwargs: Additional options.
        """
        super().__init__(
            api_key=api_key,
            model=model or self.DEFAULT_MODEL,
            base_url=base_url or self.DEFAULT_BASE_URL,
            timeout=timeout,
            **kwargs
        )

        # Validate purpose
        if upload_purpose not in self.VALID_PURPOSES:
            raise ValueError(
                f"Invalid upload_purpose: '{upload_purpose}'. "
                f"Must be one of: {self.VALID_PURPOSES}"
            )
        self.upload_purpose = upload_purpose

        self.client = OpenAI(
            api_key=self.api_key,
            base_url=self.base_url,
            timeout=self.timeout
        )
    
    def upload_file(self, file_path: Path, purpose: Optional[str] = None) -> str:
        """
        Upload file to OpenAI Files API.

        Note: OpenAI Files API is primarily for Assistants, Fine-tuning, and Batch.
        For chat completions with images, we use base64 encoding.

        Args:
            file_path: Path to file.
            purpose: Override upload purpose. If None, uses self.upload_purpose.
                    Valid: "assistants", "fine-tune", "batch", "vision".

        Returns:
            File ID.
        """
        path = self._validate_file(file_path)

        upload_purpose = purpose or self.upload_purpose
        if upload_purpose not in self.VALID_PURPOSES:
            raise ValueError(
                f"Invalid purpose: '{upload_purpose}'. "
                f"Must be one of: {self.VALID_PURPOSES}"
            )

        with open(path, "rb") as f:
            uploaded = self.client.files.create(file=f, purpose=upload_purpose)

        return uploaded.id
    
    def chat(
        self,
        prompt: str,
        files: Optional[List[Path]] = None,
        **kwargs
    ) -> Response:
        """
        Send chat request to OpenAI.
        
        Files are only accepted for image inputs. Non-image files raise ValueError
        before sending the request to OpenAI.
        """
        messages = []
        
        if files:
            # Build multimodal content
            content = []

            for file_path in files:
                path = self._validate_file(Path(file_path))
                self._check_file_size(path)  # Prevent OOM on large files
                mime_type = mimetypes.guess_type(str(path))[0] or "application/octet-stream"
                if not mime_type.startswith("image/"):
                    raise ValueError(
                        f"OpenAI chat only accepts image files via files=..., got '{path.name}' with MIME type '{mime_type}'"
                    )

                with open(path, "rb") as f:
                    b64_data = base64.b64encode(f.read()).decode("utf-8")

                content.append({
                    "type": "image_url",
                    "image_url": {
                        "url": f"data:{mime_type};base64,{b64_data}"
                    }
                })
            
            # Add text prompt
            content.append({"type": "text", "text": prompt})
            messages.append({"role": "user", "content": content})
        
        else:
            # Pure text
            messages.append({"role": "user", "content": prompt})
        
        # Build request params - only include if specified
        request_kwargs = {
            "model": self.model,
            "messages": messages,
        }
        if "temperature" in kwargs:
            request_kwargs["temperature"] = kwargs.pop("temperature")
        if "max_tokens" in kwargs:
            request_kwargs["max_tokens"] = kwargs.pop("max_tokens")
        request_kwargs.update(kwargs)
        
        # Send request
        completion = self.client.chat.completions.create(**request_kwargs)
        
        # Validate response
        if not completion.choices:
            return Response(
                content="",
                usage=Usage.from_openai(completion.usage),
                raw=completion
            )
        
        # Handle None content (e.g., when using tool_calls)
        content = completion.choices[0].message.content or ""
        
        return Response(
            content=content,
            usage=Usage.from_openai(completion.usage),
            raw=completion
        )
