"""
Client Ollama pour l'intégration LLM.

Ce module fournit une interface pour communiquer avec Ollama
et remplace les mocks LLM utilisés dans le MVP.
"""

import json
import logging
from typing import Dict, List, Optional

import requests

logger = logging.getLogger(__name__)


class OllamaClient:
    """Client pour communiquer avec Ollama."""

    def __init__(
        self,
        model: str = "mistral-large-3:675b-cloud",
        base_url: str = "http://localhost:11434",
        timeout: int = 300,
    ):
        """
        Initialise le client Ollama.

        Args:
            model: Nom du modèle Ollama à utiliser
            base_url: URL de base du serveur Ollama
            timeout: Timeout en secondes pour les requêtes
        """
        self.model = model
        self.base_url = base_url
        self.timeout = timeout
        logger.info(f"OllamaClient initialisé avec modèle: {model}")

    def generate(
        self,
        prompt: str,
        system: Optional[str] = None,
        temperature: float = 0.1,
        max_tokens: Optional[int] = None,
    ) -> str:
        """
        Génère une réponse à partir d'un prompt.

        Args:
            prompt: Le prompt utilisateur
            system: Le prompt système (optionnel)
            temperature: Température de génération (0.0 = déterministe, 1.0 = créatif)
            max_tokens: Nombre maximum de tokens à générer

        Returns:
            La réponse générée par le modèle

        Raises:
            RuntimeError: Si la requête échoue
        """
        url = f"{self.base_url}/api/generate"
        
        payload = {
            "model": self.model,
            "prompt": prompt,
            "stream": False,
            "options": {
                "temperature": temperature,
            }
        }
        
        if system:
            payload["system"] = system
        
        if max_tokens:
            payload["options"]["num_predict"] = max_tokens

        try:
            logger.debug(f"Envoi requête à Ollama: {len(prompt)} caractères")
            response = requests.post(url, json=payload, timeout=self.timeout)
            response.raise_for_status()
            
            result = response.json()
            generated_text = result.get("response", "")
            
            logger.debug(f"Réponse reçue: {len(generated_text)} caractères")
            return generated_text
            
        except requests.exceptions.Timeout:
            logger.error(f"Timeout après {self.timeout}s")
            raise RuntimeError(f"Ollama timeout après {self.timeout}s")
        except requests.exceptions.RequestException as e:
            logger.error(f"Erreur Ollama: {e}")
            raise RuntimeError(f"Erreur de communication avec Ollama: {e}")
        except Exception as e:
            logger.error(f"Erreur inattendue: {e}")
            raise RuntimeError(f"Erreur lors de la génération: {e}")

    def generate_json(
        self,
        prompt: str,
        system: Optional[str] = None,
        temperature: float = 0.1,
    ) -> Dict:
        """
        Génère une réponse JSON structurée.

        Args:
            prompt: Le prompt utilisateur
            system: Le prompt système (optionnel)
            temperature: Température de génération

        Returns:
            La réponse parsée en JSON

        Raises:
            RuntimeError: Si la génération ou le parsing échoue
        """
        # Ajouter instruction JSON au prompt
        json_prompt = f"{prompt}\n\nRéponds UNIQUEMENT avec du JSON valide, sans texte avant ou après."
        
        response = self.generate(
            prompt=json_prompt,
            system=system,
            temperature=temperature
        )
        
        # Extraire le JSON de la réponse
        try:
            # Chercher le JSON dans la réponse (peut être entouré de ```json```)
            response = response.strip()
            
            # Retirer les balises markdown si présentes
            if response.startswith("```json"):
                response = response[7:]
            if response.startswith("```"):
                response = response[3:]
            if response.endswith("```"):
                response = response[:-3]
            
            response = response.strip()
            
            return json.loads(response)
            
        except json.JSONDecodeError as e:
            logger.error(f"Erreur parsing JSON: {e}")
            logger.error(f"Réponse brute: {response[:500]}")
            raise RuntimeError(f"Impossible de parser la réponse JSON: {e}")

    def check_availability(self) -> bool:
        """
        Vérifie si Ollama est disponible.

        Returns:
            True si Ollama répond, False sinon
        """
        try:
            response = requests.get(f"{self.base_url}/api/tags", timeout=5)
            return response.status_code == 200
        except:
            return False
