from __future__ import annotations

import json
import urllib.error
import urllib.request


def chat_completion(
    provider: str,
    api_key: str,
    model: str,
    system_prompt: str,
    user_prompt: str,
    *,
    temperature: float = 0.65,
    max_tokens: int = 16384,
) -> str:
    provider = provider.lower()
    if provider == "openai":
        return _openai(api_key, model, system_prompt, user_prompt, temperature, max_tokens)
    if provider == "anthropic":
        return _anthropic(api_key, model, system_prompt, user_prompt, temperature, max_tokens)
    if provider == "gemini":
        return _gemini(api_key, model, system_prompt, user_prompt, temperature)
    raise ValueError(f"Fournisseur LLM inconnu : {provider}")


def _post_json(url: str, headers: dict[str, str], payload: dict) -> dict:
    data = json.dumps(payload).encode("utf-8")
    req = urllib.request.Request(url, data=data, headers=headers, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=600) as resp:
            return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        body = e.read().decode(errors="replace")
        try:
            err = json.loads(body)
            msg = err.get("error", {}).get("message") or err.get("message") or body[:500]
        except json.JSONDecodeError:
            msg = body[:500]
        raise RuntimeError(f"LLM HTTP {e.code} : {msg}") from e


def _openai(
    api_key: str,
    model: str,
    system_prompt: str,
    user_prompt: str,
    temperature: float,
    max_tokens: int,
) -> str:
    data = _post_json(
        "https://api.openai.com/v1/chat/completions",
        {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        },
        {
            "model": model,
            "messages": [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_prompt},
            ],
            "temperature": temperature,
            "max_tokens": max_tokens,
        },
    )
    return data["choices"][0]["message"]["content"]


def _anthropic(
    api_key: str,
    model: str,
    system_prompt: str,
    user_prompt: str,
    temperature: float,
    max_tokens: int,
) -> str:
    data = _post_json(
        "https://api.anthropic.com/v1/messages",
        {
            "x-api-key": api_key,
            "anthropic-version": "2023-06-01",
            "Content-Type": "application/json",
        },
        {
            "model": model,
            "max_tokens": max_tokens,
            "temperature": temperature,
            "system": system_prompt,
            "messages": [{"role": "user", "content": user_prompt}],
        },
    )
    for block in data.get("content", []):
        if block.get("type") == "text":
            return block.get("text", "")
    return ""


def _gemini(
    api_key: str,
    model: str,
    system_prompt: str,
    user_prompt: str,
    temperature: float,
) -> str:
    url = (
        f"https://generativelanguage.googleapis.com/v1beta/models/"
        f"{urllib.request.quote(model, safe='')}:generateContent?key={urllib.request.quote(api_key, safe='')}"
    )
    combined = f"{system_prompt}\n\n---\n\n{user_prompt}"
    data = _post_json(
        url,
        {"Content-Type": "application/json"},
        {
            "contents": [{"role": "user", "parts": [{"text": combined}]}],
            "generationConfig": {"temperature": temperature},
        },
    )
    parts = data.get("candidates", [{}])[0].get("content", {}).get("parts", [])
    return parts[0].get("text", "") if parts else ""
