"""
AI backend for goCLI.

Sends the detected error and recent shell context to Google Gemini Flash
and returns a single fix command as a plain string.

To swap to another provider (OpenAI, Anthropic, etc.) replace the
`get_fix` function while keeping the same signature.
"""

from __future__ import annotations

import json
import urllib.request
import urllib.error
from typing import Optional

from .config import (
    GEMINI_API_KEY,
    GEMINI_ENDPOINT,
    GEMINI_MODEL,
    AI_TIMEOUT,
)


_SYSTEM_PROMPT: str = (
    "You are a terminal error assistant. The user will give you a terminal "
    "error message and recent command history. Respond with ONLY a single "
    "shell command that fixes the issue. No explanation, no markdown, no "
    "code fences, no extra text. Just the command. If no fix is possible, "
    "reply with a single short sentence explaining why."
)


def get_fix(error_text: str, recent_commands: list[str]) -> Optional[str]:
    """Return a fix command for *error_text*, or ``None`` on failure.

    Parameters
    ----------
    error_text:
        The raw error output captured from the terminal.
    recent_commands:
        The last N commands the user executed (most recent last).
    """
    context = "\n".join(recent_commands) if recent_commands else "(no history)"

    user_message = (
        f"Error:\n{error_text}\n\n"
        f"Recent commands:\n{context}"
    )

    payload = {
        "contents": [
            {
                "role": "user",
                "parts": [
                    {"text": f"{_SYSTEM_PROMPT}\n\n{user_message}"}
                ],
            }
        ],
        "generationConfig": {
            "temperature": 0.0,
            "maxOutputTokens": 256,
        },
    }

    url = GEMINI_ENDPOINT.format(model=GEMINI_MODEL)
    headers = {
        "Content-Type": "application/json",
        "X-goog-api-key": GEMINI_API_KEY,
    }

    req = urllib.request.Request(
        url,
        data=json.dumps(payload).encode(),
        headers=headers,
        method="POST",
    )

    try:
        with urllib.request.urlopen(req, timeout=AI_TIMEOUT) as resp:
            body = json.loads(resp.read().decode())
    except urllib.error.HTTPError as exc:
        # Surface the HTTP error code so the user knows what's wrong.
        try:
            err_body = json.loads(exc.read().decode())
            msg = err_body.get("error", {}).get("message", str(exc))
        except Exception:
            msg = str(exc)
        import sys
        from .config import LABEL, MUTED, CORAL, RESET
        sys.stderr.write(f"  {LABEL}  {CORAL}API error {exc.code}: {msg}{RESET}\n")
        if exc.code in (400, 403):
            sys.stderr.write(
                f"         {MUTED}set your own key: "
                f"{CORAL}set GOCLI_API_KEY=<your-key>{RESET}\n"
                f"         {MUTED}get one free at {CORAL}aistudio.google.com{RESET}\n"
            )
        sys.stderr.flush()
        return None
    except (urllib.error.URLError, TimeoutError, OSError):
        return None

    # Parse Gemini response.
    try:
        candidates = body["candidates"]
        text: str = candidates[0]["content"]["parts"][0]["text"]
        return text.strip()
    except (KeyError, IndexError):
        return None
