"""Ollama local AI provider implementation."""

from __future__ import annotations

import json
from typing import Any

import requests
from requests import Response
from requests.exceptions import RequestException

from app.services.ai.providers.base import (
    AIProvider,
    AIProviderResponseError,
    AIProviderUnavailableError,
)

DEFAULT_OLLAMA_BASE_URL = "http://localhost:11434"
DEFAULT_OLLAMA_MODEL = "llama3.2:3b"
DEFAULT_TIMEOUT_SECONDS = 45
HEALTH_TIMEOUT_SECONDS = 0.8


def _response_error_detail(response: Response) -> str:
    """Extract concise API error details from Ollama response."""
    try:
        payload = response.json()
    except ValueError:
        text = response.text.strip()
        return text or "Ollama request failed"

    if isinstance(payload, dict):
        value = payload.get("error") or payload.get("detail") or payload.get("message")
        if isinstance(value, str) and value.strip():
            return value.strip()
    return "Ollama request failed"


def _prompt_with_context(prompt: str, context: dict[str, Any] | None) -> str:
    """Merge context into prompt for local generation."""
    clean_prompt = str(prompt or "").strip()
    if not context:
        return clean_prompt
    return f"{clean_prompt}\n\nContext:\n{json.dumps(context, ensure_ascii=False, indent=2)}"


class OllamaProvider(AIProvider):
    """Local Ollama provider via /api/generate."""

    def __init__(
        self,
        model: str = DEFAULT_OLLAMA_MODEL,
        base_url: str = DEFAULT_OLLAMA_BASE_URL,
        timeout_seconds: float = DEFAULT_TIMEOUT_SECONDS,
    ):
        self._base_url = (base_url or DEFAULT_OLLAMA_BASE_URL).rstrip("/")
        self._model = str(model or "").strip() or DEFAULT_OLLAMA_MODEL
        self._timeout_seconds = max(float(timeout_seconds), 1.0)

    def provider_name(self) -> str:
        return "ollama"

    def _generate_request(self, *, prompt: str, timeout_seconds: float) -> Response:
        body = {
            "model": self._model,
            "prompt": prompt,
            "stream": False,
            "options": {"temperature": 0.35},
        }
        try:
            return requests.post(
                url=f"{self._base_url}/api/generate",
                json=body,
                timeout=max(timeout_seconds, 0.2),
            )
        except RequestException as exc:
            raise AIProviderUnavailableError(f"Ollama request failed: {exc}") from exc

    def generate(self, prompt: str, context: dict[str, Any] | None = None) -> str:
        response = self._generate_request(
            prompt=_prompt_with_context(prompt, context),
            timeout_seconds=self._timeout_seconds,
        )
        if response.status_code != 200:
            raise AIProviderResponseError(
                f"Ollama API request failed ({response.status_code}): {_response_error_detail(response)}",
            )
        try:
            payload = response.json()
        except ValueError as exc:
            raise AIProviderResponseError("Ollama returned invalid JSON body") from exc

        text = payload.get("response") if isinstance(payload, dict) else None
        if not isinstance(text, str) or not text.strip():
            raise AIProviderResponseError("Ollama returned an empty response")
        return text.strip()

    def health_check(self) -> bool:
        try:
            response = self._generate_request(
                prompt="Reply exactly: ok",
                timeout_seconds=HEALTH_TIMEOUT_SECONDS,
            )
        except AIProviderUnavailableError:
            return False
        return response.status_code == 200
