"""
Web search service using Google Gemini via Vertex AI with search grounding.

Uses the Google GenAI SDK (Vertex AI) to perform a grounded search query and
returns a summarised result that the voice agent can speak aloud, plus
structured source links for the Android app to display.
"""

import json
import os

from loguru import logger

try:
    from google import genai
    from google.genai.types import GenerateContentConfig, GoogleSearch, Tool
    from google.oauth2 import service_account
except ImportError as exc:
    logger.error(f"google-genai package is required for search: {exc}")
    raise


def _get_vertex_client() -> genai.Client:
    """Create a Vertex AI GenAI client using service account credentials."""
    creds_path = os.getenv("GOOGLE_CREDENTIALS_PATH")
    creds_json = os.getenv("GOOGLE_CREDENTIALS_JSON")
    project_id = os.getenv("GOOGLE_PROJECT_ID")

    if creds_json:
        creds = service_account.Credentials.from_service_account_info(
            json.loads(creds_json),
            scopes=["https://www.googleapis.com/auth/cloud-platform"],
        )
    elif creds_path:
        creds = service_account.Credentials.from_service_account_file(
            creds_path,
            scopes=["https://www.googleapis.com/auth/cloud-platform"],
        )
    else:
        raise ValueError("GOOGLE_CREDENTIALS_PATH or GOOGLE_CREDENTIALS_JSON must be set")

    return genai.Client(
        vertexai=True,
        credentials=creds,
        project=project_id,
        location="asia-south1",
    )


def _extract_sources(response) -> list[dict]:
    """Extract source links from Gemini grounding metadata.

    Returns a list of dicts with keys: title, url, domain.
    """
    sources = []
    seen_urls = set()

    try:
        candidates = getattr(response, "candidates", None)
        if not candidates:
            return sources

        for candidate in candidates:
            metadata = getattr(candidate, "grounding_metadata", None)
            if not metadata:
                continue

            # groundingChunks contain the web sources
            chunks = getattr(metadata, "grounding_chunks", None)
            if not chunks:
                continue

            for chunk in chunks:
                web = getattr(chunk, "web", None)
                if not web:
                    continue

                uri = getattr(web, "uri", "")
                title = getattr(web, "title", "")

                if uri and uri not in seen_urls:
                    seen_urls.add(uri)
                    sources.append({
                        "title": title or uri,
                        "url": uri,
                        "domain": getattr(web, "domain", ""),
                    })

    except Exception as e:
        logger.warning(f"[Search] Could not extract grounding sources: {e}")

    return sources


async def web_search(query: str) -> dict:
    """Perform a web search using Gemini via Vertex AI with Google Search grounding.

    Args:
        query: The search query string.

    Returns:
        dict with keys:
            - success (bool)
            - summary (str): Summarised search results ready for TTS.
            - sources (list[dict]): Source links with title, url, domain.
            - error (str, optional): Error message on failure.
    """
    try:
        logger.info(f"[Search] Querying: {query!r}")

        client = _get_vertex_client()

        # Use Gemini with Google Search grounding to get real-time results
        response = await client.aio.models.generate_content(
            model="gemini-2.5-flash",
            contents=f"Search the web and provide a concise summary for: {query}",
            config=GenerateContentConfig(
                tools=[Tool(google_search=GoogleSearch())],
                temperature=0.3,
            ),
        )

        summary = response.text.strip() if response.text else "No results found."
        sources = _extract_sources(response)

        logger.info(f"[Search] Got response ({len(summary)} chars, {len(sources)} sources)")

        return {"success": True, "summary": summary, "sources": sources}

    except Exception as e:
        logger.error(f"[Search] Error: {e}")
        return {"success": False, "error": str(e)}
