"""Natural language query engine for the SDK reference.

Resolution order:
  1. User's own GOOGLE_API_KEY (direct to Gemini) — no limits
  2. sdkspindle trial proxy — 20 queries/day/IP
  3. Offline mode — grep the JSON reference locally, no AI
"""

import json
import sys
import os
import re
import urllib.request
import urllib.error
from pathlib import Path
from typing import Optional

DEFAULT_PROXY = "https://sdkspindle.vercel.app/api/query"
DEFAULT_MODEL = "gemini-3-flash-preview"


def _load_reference(sdk_path):
    with open(sdk_path) as f:
        return json.load(f)


def _extract_relevant_context(sdk, question):
    question_lower = question.lower()
    words = set(re.findall(r'[a-z]+', question_lower))
    relevant_types, relevant_services = {}, {}
    types_db = sdk.get("types", {})
    services_db = sdk.get("services", {})
    for type_name, type_info in types_db.items():
        score = 0
        name_lower = type_name.lower()
        for word in words:
            if word in name_lower: score += 10
        for fld in type_info.get("fields", []):
            if fld["name"].lower() in words: score += 5
        for bm in type_info.get("builderMethods", []):
            if bm["name"].lower() in words: score += 5
        if score > 0: relevant_types[type_name] = type_info
    for svc_name, svc_info in services_db.items():
        score = 0
        for word in words:
            if word in svc_name.lower(): score += 10
        for method in svc_info.get("methods", []):
            if method["name"].lower() in words: score += 5
        if score > 0: relevant_services[svc_name] = svc_info
    if not relevant_types and not relevant_services:
        for name in ["GenerateContentConfig", "Content", "Part", "CreateCachedContentConfig", "CachedContent", "Blob", "ThinkingConfig"]:
            if name in types_db: relevant_types[name] = types_db[name]
        for name in ["Caches", "Models", "Chats"]:
            if name in services_db: relevant_services[name] = services_db[name]
    return json.dumps({"types": relevant_types, "services": relevant_services}, indent=2)


SYSTEM_PROMPT = """You are sdkspindle, an expert on the com.google.genai Java SDK (google-genai).
You have access to the extracted SDK API reference below.

Rules:
- Answer with EXACT Java/Kotlin types, method signatures, and field names from the reference.
- When showing code, use Kotlin syntax (the primary consumer language).
- Always show the correct import statements.
- If a field returns Optional<T>, always show the .orElse() unwrapping.
- If a builder method has varargs overloads, mention both List<T> and varargs options.
- Be concise. Developers want the answer, not an essay.
- If the question is about something not in the reference, say so clearly."""


def _query_direct(context, question, model, api_key):
    """Direct Gemini call. Requires google-genai."""
    try:
        from google import genai
    except ImportError:
        return None
    client = genai.Client(api_key=api_key)
    try:
        response = client.models.generate_content(
            model=model,
            contents=f"SDK API Reference (relevant subset):\n```json\n{context}\n```\n\nQuestion: {question}",
            config={
                "system_instruction": SYSTEM_PROMPT,
                "temperature": 0.1,
                "max_output_tokens": 2048,
            },
        )
        return response.text or "(empty response)"
    except Exception as e:
        return f"ERROR (direct): {e}"


def _query_proxy(context, question, model):
    """Trial proxy. Zero deps."""
    proxy_url = os.environ.get("SDKSPINDLE_PROXY", DEFAULT_PROXY)
    payload = json.dumps({"question": question, "context": context, "model": model}).encode("utf-8")
    req = urllib.request.Request(proxy_url, data=payload,
        headers={"Content-Type": "application/json", "User-Agent": "sdkspindle/0.1.0"}, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read())
            if "error" in data: return f"Proxy error: {data['error']}"
            return data.get("answer", "(empty)")
    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", errors="replace")
        try: msg = json.loads(body).get("error", body[:200])
        except json.JSONDecodeError: msg = body[:200]
        if e.code == 429:
            return (f"Rate limited: {msg}\n\nTrial: 20/day. For unlimited:\n"
                    "  export GOOGLE_API_KEY=your-key\n  pip install sdkspindle[query]\n"
                    "  Get a key at: https://aistudio.google.com/app/apikey")
        return f"Proxy error ({e.code}): {msg}"
    except urllib.error.URLError as e:
        return f"Proxy unreachable: {e.reason}. Use --api-key for direct mode."
    except Exception as e:
        return f"Proxy error: {e}"


def _query_offline(sdk, question):
    """Grep the JSON. No API."""
    question_lower = question.lower()
    words = set(re.findall(r'[a-z]{3,}', question_lower))
    results = []
    for type_name, type_info in sdk.get("types", {}).items():
        if any(w in type_name.lower() for w in words):
            fields_str = "".join(f"    .{f['name']}(): {f['type']}{' (Optional)' if f.get('optional') else ''}\n" for f in type_info.get("fields", []))
            builder_str = "".join(f"    .{m['name']}({m['paramType']}){' [varargs]' if m.get('varargs') else ''}\n" for m in type_info.get("builderMethods", []))
            r = f"\n  {type_name}\n"
            if fields_str: r += f"  Fields:\n{fields_str}"
            if builder_str: r += f"  Builder:\n{builder_str}"
            results.append(r)
    for svc_name, svc_info in sdk.get("services", {}).items():
        if any(w in svc_name.lower() for w in words):
            methods_str = "".join(f"    .{m['name']}({', '.join(p['type']+' '+p['name'] for p in m.get('params',[]))}) -> {m.get('returnType','?')}\n" for m in svc_info.get("methods", []))
            results.append(f"\n  {svc_name} (service)\n  Methods:\n{methods_str}")
    if not results: return f"No matches for: {question}"
    seen = set()
    unique = [r for r in results if r not in seen and not seen.add(r)]
    return f"  Offline: {len(unique)} result(s) for \"{question}\"\n  {'\u2500'*50}\n" + "\n".join(unique[:30])


def query_sdk(sdk_path, question, model=DEFAULT_MODEL, api_key=None,
              offline=False, force_direct=False, force_proxy=False):
    sdk = _load_reference(sdk_path)
    if offline: return _query_offline(sdk, question)
    context = _extract_relevant_context(sdk, question)
    resolved_key = api_key or os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY")
    if resolved_key and not force_proxy:
        result = _query_direct(context, question, model, resolved_key)
        if result is not None: return result
        print("  (google-genai not installed, falling back to proxy)", file=sys.stderr)
    if force_direct:
        return "ERROR: --direct requires GOOGLE_API_KEY and google-genai installed."
    return _query_proxy(context, question, model)
