"""
Ollama LLM client implementation.
"""

import json
import logging
from typing import Optional, Dict, Any
import urllib.request
import urllib.error

from .base import LLMClient, LLMResponse


logger = logging.getLogger(__name__)


class OllamaClient(LLMClient):
    """
    LLM client for Ollama.
    
    Example:
        client = OllamaClient(model="deepseek-coder-v2:16b")
        response = client.generate("Write hello world in Python")
    """
    
    DEFAULT_BASE_URL = "http://localhost:11434"
    
    def __init__(
        self,
        model: str = "llama3:8b",
        base_url: Optional[str] = None,
        timeout: int = 300,
        temperature: float = 0.7,
        top_p: float = 0.9,
        **kwargs
    ):
        super().__init__(
            model=model,
            base_url=base_url or self.DEFAULT_BASE_URL,
            timeout=timeout,
            **kwargs
        )
        self.temperature = temperature
        self.top_p = top_p
        logger.info(f"Initialized OllamaClient with model: {model}")
    
    def generate(
        self,
        prompt: str,
        system_prompt: Optional[str] = None,
        model: Optional[str] = None,
        **kwargs
    ) -> LLMResponse:
        """Generate a response using Ollama."""
        use_model = self.get_model(model)
        
        # Build messages
        messages = []
        if system_prompt:
            messages.append({"role": "system", "content": system_prompt})
        messages.append({"role": "user", "content": prompt})
        
        # Build request
        payload = {
            "model": use_model,
            "messages": messages,
            "stream": False,
            "options": {
                "temperature": kwargs.get("temperature", self.temperature),
                "top_p": kwargs.get("top_p", self.top_p),
            }
        }
        
        url = f"{self.base_url}/api/chat"
        
        try:
            data = json.dumps(payload).encode("utf-8")
            req = urllib.request.Request(
                url,
                data=data,
                headers={"Content-Type": "application/json"},
                method="POST"
            )
            
            with urllib.request.urlopen(req, timeout=self.timeout) as response:
                result = json.loads(response.read().decode("utf-8"))
            
            content = result.get("message", {}).get("content", "")
            
            return LLMResponse(
                content=content,
                model=use_model,
                tokens_used=result.get("eval_count", 0) + result.get("prompt_eval_count", 0),
                metadata={
                    "total_duration": result.get("total_duration"),
                    "load_duration": result.get("load_duration"),
                    "eval_duration": result.get("eval_duration"),
                }
            )
            
        except urllib.error.URLError as e:
            logger.error(f"Failed to connect to Ollama: {e}")
            raise ConnectionError(f"Cannot connect to Ollama at {self.base_url}: {e}")
        except Exception as e:
            logger.error(f"Ollama request failed: {e}")
            raise
    
    def is_available(self) -> bool:
        """Check if Ollama is running and accessible."""
        try:
            url = f"{self.base_url}/api/tags"
            req = urllib.request.Request(url, method="GET")
            with urllib.request.urlopen(req, timeout=5) as response:
                return response.status == 200
        except Exception:
            return False
    
    def list_models(self) -> list:
        """List available models in Ollama."""
        try:
            url = f"{self.base_url}/api/tags"
            req = urllib.request.Request(url, method="GET")
            with urllib.request.urlopen(req, timeout=10) as response:
                result = json.loads(response.read().decode("utf-8"))
                return [m["name"] for m in result.get("models", [])]
        except Exception as e:
            logger.error(f"Failed to list models: {e}")
            return []
