"""Google Gemini sağlayıcısı — YALNIZCA kamuya açık veri görevleri için.

Bu modül `router.Sensitivity.PUBLIC` işaretli görevlerde kullanılır. Gizlilik
sınırı `router.TaskSpec` içinde zorlanır: `CONFIDENTIAL` bir görev buraya
yönlendirilemez (import anında ValueError).

Tasarım kararı — **yumuşak bağımlılık**: Gemini yapılandırılmamışsa veya
çağrı başarısız olursa çağıran taraf Claude'a düşer. PUBLIC görevlerde her
iki sağlayıcı da hukuken uygun olduğu için fallback güvenlidir; bu sayede
`GEMINI_API_KEY` olmayan bir ortamda (CI, yerel geliştirme) hiçbir şey
bozulmaz.
"""

from __future__ import annotations

import logging
from functools import lru_cache
from typing import Any

from pydantic import BaseModel

from app.config import get_settings

logger = logging.getLogger(__name__)


class GeminiNotConfiguredError(RuntimeError):
    """GEMINI_API_KEY tanımlı değil — çağıran taraf Claude'a düşmeli."""


@lru_cache
def _client() -> Any:
    """Global async-capable Gemini client.

    `google-genai` import'u fonksiyon içindedir: paket kurulu değilse modül
    import'u patlamasın, yalnızca fiilen Gemini çağrılırsa hata versin.
    """
    settings = get_settings()
    if not settings.gemini_api_key:
        raise GeminiNotConfiguredError("GEMINI_API_KEY tanımlı değil.")
    try:
        from google import genai
    except ImportError as exc:  # pragma: no cover - kurulum sorunu
        raise GeminiNotConfiguredError(
            "google-genai paketi kurulu değil: pip install google-genai"
        ) from exc
    return genai.Client(api_key=settings.gemini_api_key)


def is_configured() -> bool:
    """Gemini kullanılabilir mi? Çağıran taraf fallback kararı için kullanır."""
    try:
        _client()
    except GeminiNotConfiguredError:
        return False
    except Exception:  # noqa: BLE001 - beklenmedik kurulum hatası
        return False
    return True


def usage_as_record(usage_metadata: Any) -> dict[str, int]:
    """Gemini `usage_metadata`'yı `record_usage()`'ın beklediği şekle çevirir.

    Gemini alan adları Anthropic'ten farklı; ortak maliyet borusunu tek
    formatta tutmak için burada eşliyoruz.

    Not: Gemini'de `prompt_token_count`, cache kullanıldığında cache'lenmiş
    token'ları DA içerir. Anthropic'te `input_tokens` cache'lenmemiş kısımdır.
    Çift sayımı önlemek için cache'li kısmı düşüyoruz.
    """
    if usage_metadata is None:
        return {}

    def _get(name: str) -> int:
        return int(getattr(usage_metadata, name, 0) or 0)

    prompt = _get("prompt_token_count")
    cached = _get("cached_content_token_count")
    return {
        "input_tokens": max(prompt - cached, 0),
        "output_tokens": _get("candidates_token_count"),
        "cache_creation_input_tokens": 0,  # Gemini explicit cache API'si kullanılmıyor
        "cache_read_input_tokens": cached,
    }


async def generate_structured[T: BaseModel](
    *,
    model: str,
    system: str,
    user: str,
    schema: type[T],
    max_tokens: int,
) -> tuple[T | None, dict[str, int]]:
    """Şema-doğrulanmış JSON üret.

    Returns:
        (parsed, usage_record). Parse edilemezse (None, usage).

    Raises:
        GeminiNotConfiguredError: yapılandırma yoksa — çağıran Claude'a düşer.
    """
    from google.genai import types

    client = _client()
    response = await client.aio.models.generate_content(
        model=model,
        contents=user,
        config=types.GenerateContentConfig(
            system_instruction=system,
            response_mime_type="application/json",
            response_schema=schema,
            max_output_tokens=max_tokens,
        ),
    )

    usage = usage_as_record(getattr(response, "usage_metadata", None))

    # `.parsed` bir Field'dir (property değil); response_schema verildiğinde
    # doldurulur, aksi halde None kalır.
    parsed = getattr(response, "parsed", None)
    if parsed is not None and not isinstance(parsed, schema):
        # SDK dict döndürdüyse Pydantic'e geçir.
        try:
            parsed = schema.model_validate(parsed)
        except Exception as exc:  # noqa: BLE001
            logger.warning("Gemini yanıtı şemaya uymadı: %s", exc)
            parsed = None

    return parsed, usage
