"""
Google Gemini LLM Provider Adapter

Adapter for Google's Gemini models via FastMCP.

v2.0: Includes event emission for tool calls and real-time visibility.
"""

import time
from typing import Callable

from google import genai
from google.genai import types

from honeydb_ai.domain.exceptions import (
    LLMAPIError,
    LLMProviderError,
    LLMRateLimitError,
    LLMRequestCancelledError,
)
from honeydb_ai.domain.models import Event, LLMResponse, Message
from honeydb_ai.infrastructure.llm_adapters.base import BaseLLMAdapter


class GeminiAdapter(BaseLLMAdapter):
    """
    Google Gemini provider adapter.

    Supports Gemini 3.1 preview models (see ``get_available_models``), including:
      - gemini-3.1-pro-preview-customtools
      - gemini-3.1-pro-preview
      - gemini-3.1-flash-preview
      - gemini-3.1-flash-lite

    Uses FastMCP for MCP tool integration.
    """

    def __init__(self, api_key: str):
        """
        Initialize Gemini adapter.

        Args:
            api_key: Google AI API key
        """
        super().__init__(api_key)
        self.client = genai.Client(api_key=api_key)

    async def send_message(
        self,
        messages: list[Message],
        model: str | None = None,
        temperature: float | None = None,
        max_tokens: int | None = None,
        stream: bool = False,
        event_callback: Callable[[Event], None] | None = None,
    ) -> LLMResponse:
        """
        Send messages to Gemini API.

        v2.0: Emits events for request lifecycle and tool calls.

        Args:
            messages: List of messages in the conversation
            model: Model identifier (e.g., "gemini-3.1-pro-preview-customtools")
            temperature: Sampling temperature (0.0-1.0)
            max_tokens: Maximum tokens in response
            stream: Whether to stream response (Phase 1: False)
            event_callback: Optional callback for events

        Returns:
            LLMResponse with the assistant's response

        Raises:
            LLMProviderError: If the provider returns an error
            LLMAPIError: If the API call fails
            LLMRateLimitError: If rate limit is exceeded
            LLMRequestCancelledError: If user cancels the request
        """
        model = model or "gemini-3.1-pro-preview-customtools"
        start_time = time.time()

        # Emit request started event
        self._emit_request_started(event_callback, model, len(messages))

        # Convert messages to Gemini format
        # Gemini uses "user" and "model" roles (not "assistant")
        api_messages = []
        for msg in messages:
            role = "model" if msg.role == "assistant" else msg.role
            api_messages.append({
                "role": role,
                "parts": [{"text": msg.content}]
            })

        # Build generation config
        generation_config = {}
        if temperature is not None:
            generation_config["temperature"] = temperature
        if max_tokens is not None:
            generation_config["max_output_tokens"] = max_tokens

        try:
            # Make API call
            response = self.client.models.generate_content(
                model=model,
                contents=api_messages,
                config=types.GenerateContentConfig(**generation_config) if generation_config else None,
            )

            # Extract response
            content = ""
            if response.text:
                content = response.text

            # Check for tool calls (function calls in Gemini)
            if hasattr(response, 'candidates') and response.candidates:
                candidate = response.candidates[0]
                if hasattr(candidate, 'content') and hasattr(candidate.content, 'parts'):
                    for part in candidate.content.parts:
                        if hasattr(part, 'function_call'):
                            self._emit_tool_call(
                                event_callback,
                                part.function_call.name,
                                {"args": dict(part.function_call.args)}
                            )

            finish_reason = None
            if hasattr(response, 'candidates') and response.candidates:
                finish_reason = str(response.candidates[0].finish_reason)

            # Calculate duration
            duration_ms = (time.time() - start_time) * 1000

            # Emit response received event
            self._emit_response_received(event_callback, finish_reason, duration_ms)

            # Log (metadata only)
            self.logger.info(
                f"Gemini request completed | Model: {model} | "
                f"Duration: {duration_ms:.0f}ms | Finish: {finish_reason}"
            )

            # Build response
            usage = {}
            if hasattr(response, 'usage_metadata'):
                usage = {
                    "prompt_tokens": response.usage_metadata.prompt_token_count,
                    "completion_tokens": response.usage_metadata.candidates_token_count,
                    "total_tokens": response.usage_metadata.total_token_count,
                }

            return LLMResponse(
                content=content,
                model=model,
                finish_reason=finish_reason,
                usage=usage,
                metadata={}
            )

        except KeyboardInterrupt:
            self.logger.info("Gemini request cancelled by user")
            raise LLMRequestCancelledError()

        except Exception as e:
            error_str = str(e).lower()

            # Check for rate limit errors
            if "rate limit" in error_str or "quota" in error_str:
                self.logger.warning(f"Gemini rate limit exceeded: {e}")
                raise LLMRateLimitError("Gemini", None)

            # Check for API errors
            if "api" in error_str or "http" in error_str:
                self.logger.error(f"Gemini API error: {e}")
                raise LLMAPIError("Gemini", 0, str(e))

            # Generic provider error
            self.logger.error(f"Unexpected Gemini error: {e}")
            raise LLMProviderError("Gemini", str(e))

    def validate_api_key(self) -> bool:
        """
        Validate that the API key is configured.

        Returns:
            True if API key is present and non-empty
        """
        return bool(self.api_key and len(self.api_key.strip()) > 0)

    def get_provider_name(self) -> str:
        """Get the provider name."""
        return "gemini"

    def get_available_models(self) -> list[str]:
        """
        Get list of available Gemini models.

        Returns:
            List of model identifiers
        """
        return [
            "gemini-3.1-pro-preview-customtools",
            "gemini-3.1-pro-preview",
            "gemini-3.1-flash-preview",
            "gemini-3.1-flash-lite",
        ]
