"""Abstract base class for vendor adapters."""

from abc import ABC, abstractmethod
from pathlib import Path
from typing import List, Optional, Any

from ..models import Response


class VendorAdapter(ABC):
    """
    Abstract base class for AI vendor adapters.

    All vendor implementations must inherit from this class and implement
    the required methods. The adapter is responsible for:
    1. Uploading files to vendor's File API
    2. Sending chat requests
    3. Returning raw, unmodified AI responses
    """

    # Maximum file size for inline base64 encoding (20MB)
    MAX_INLINE_FILE_SIZE = 20 * 1024 * 1024

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

        Args:
            api_key: Vendor API key.
            model: Model name to use. If None, adapter's DEFAULT_MODEL is used.
            base_url: Optional custom API endpoint (for relays/proxies).
            timeout: Optional request timeout in seconds.
            **kwargs: Additional vendor-specific options.
        """
        if not api_key:
            raise ValueError("API key is required")

        self.api_key = api_key
        self.model = model  # Allow None, subclass will use DEFAULT_MODEL
        self.base_url = base_url
        self.timeout = timeout
        self.options = kwargs
    
    @abstractmethod
    def chat(
        self,
        prompt: str,
        files: Optional[List[Path]] = None,
        **kwargs
    ) -> Response:
        """
        Send a chat request to the AI model.
        
        Args:
            prompt: User prompt text.
            files: Optional list of file paths to include (will be uploaded via File API).
            **kwargs: Additional request parameters (temperature, max_tokens, etc.)
        
        Returns:
            Response object with raw content and usage stats.
        """
        ...
    
    @abstractmethod
    def upload_file(self, file_path: Path) -> str:
        """
        Upload a file to the vendor's File API.
        
        Args:
            file_path: Path to the file to upload.
        
        Returns:
            File ID or URI for referencing in chat requests.
        """
        ...
    
    def _validate_file(self, file_path: Path) -> Path:
        """Validate that path exists, is a file, and return resolved path."""
        path = Path(file_path)
        if not path.exists():
            raise FileNotFoundError(f"File not found: {file_path}")
        if not path.is_file():
            raise ValueError(f"Path is not a file: {file_path}")
        return path.resolve()

    def _check_file_size(self, file_path: Path, max_size: Optional[int] = None) -> None:
        """
        Check if file size is within limit for inline base64 encoding.

        Args:
            file_path: Path to the file.
            max_size: Maximum allowed size in bytes. Defaults to MAX_INLINE_FILE_SIZE.

        Raises:
            ValueError: If file exceeds the size limit.
        """
        max_size = max_size or self.MAX_INLINE_FILE_SIZE
        size = file_path.stat().st_size
        if size > max_size:
            raise ValueError(
                f"File too large for inline encoding: {file_path.name} ({size / 1024 / 1024:.1f}MB). "
                f"Maximum allowed: {max_size / 1024 / 1024:.1f}MB. "
                f"Consider using the vendor's File API instead."
            )

    @staticmethod
    def _extract_text_from_content(content: Any) -> str:
        """
        Extract text from various content formats returned by different SDKs.

        This helper handles common patterns:
        - str: return as-is
        - list of str/dict: extract text fields and join
        - object with .text attribute: return .text

        Args:
            content: Content from SDK response (str, list, or object).

        Returns:
            Extracted text string.
        """
        if content is None:
            return ""
        if isinstance(content, str):
            return content
        if isinstance(content, list):
            parts = []
            for item in content:
                if isinstance(item, str):
                    parts.append(item)
                elif isinstance(item, dict):
                    text = item.get("text") or item.get("content")
                    if text:
                        parts.append(text)
                else:
                    text = getattr(item, "text", None) or getattr(item, "content", None)
                    if text:
                        parts.append(text)
            return "\n".join(parts)
        # Try common attributes
        text = getattr(content, "text", None) or getattr(content, "content", None)
        if text:
            return str(text)
        return str(content) if content else ""
