
"""
Serviciu pentru comunicare cu API-ul Ollama
Adaptare logică din v4.py la async/await cu httpx
"""
import httpx
import json
import asyncio
from typing import Dict, Any, List, AsyncGenerator, Optional
from .models import Agent


MAX_RETRY = 3
INTREBARE_IMPLICITA = "Ce idei concrete, ne-repetate, poți adăuga mai departe?"


def sistem_role_prompt(subiect: str, rol: str, max_tokens: int) -> str:
    """
    Generează prompt-ul de sistem bazat pe rolul agentului
    Adaptat din v4.py
    """
    baza = (
        f"Discuți despre: {subiect}. Răspunde concis (max {max_tokens} tokeni), clar, în română.\n"
        "Reguli generale:\n"
        "1) Evită repetițiile. 2) Adaugă cel puțin O IDEE NOUĂ față de lista 'Idei deja menționate'. "
        "3) Listează ideile ca bullets scurte, concrete, testabile. 4) Fii specific (cifre, condiții, costuri, pași)."
    )
    
    if rol == "generator":
        return baza + "\nRol: GENERATOR – propune idei noi, combinații neobișnuite, dar plauzibile."
    elif rol == "critic":
        return baza + "\nRol: CRITIC – semnalează riscuri/limitări și oferă o îmbunătățire alternativă pentru fiecare punct."
    elif rol == "moderator":
        return baza + "\nRol: MODERATOR – impune noutatea, rezumă scurt progresul, pune o întrebare-țintă pentru runda următoare."
    elif rol in ("synth", "sintetizator", "synthesizer"):
        return baza + "\nRol: SINTETIZATOR – combină cele mai bune idei, elimină redundanța, propune o mini-foaie de parcurs."
    else:
        return baza + "\nRol: GENERAL – adaugă idei utile și noi."


def construieste_mesaje(
    conversatie: List[Dict[str, str]], 
    subiect: str, 
    rol: str, 
    max_tokens: int, 
    idei_deja: List[str]
) -> List[Dict[str, str]]:
    """
    Construiește lista de mesaje pentru API-ul Ollama
    Include sistemul, istoricul și instrucțiunile de unicitate
    """
    sistem = sistem_role_prompt(subiect, rol, max_tokens)
    
    # Limitează la ultimele 30 de idei pentru a nu supraîncărca contextul
    idei_block = (
        "Idei deja menționate până acum:\n- " + "\n- ".join(idei_deja[-30:]) 
        if idei_deja 
        else "Nu există idei înregistrate încă."
    )
    
    instructiune = (
        f"{idei_block}\n"
        "Asigură-te că fiecare punct nou este ne-repetat față de listă. "
        f"După idei, încheie cu: 'NEXT: {INTREBARE_IMPLICITA}'"
    )
    
    # Construiește mesajele
    messages = [{"role": "system", "content": sistem}]
    messages.extend(conversatie)
    messages.append({"role": "user", "content": instructiune})
    
    return messages


async def get_available_models(ip: str, port: str = "11434", timeout: int = 10) -> List[str]:
    """
    Obține lista de modele disponibile de la un server Ollama
    
    Args:
        ip: Adresa IP a serverului Ollama
        port: Portul serverului Ollama
        timeout: Timeout pentru cerere în secunde
        
    Returns:
        Lista de nume de modele disponibile
    """
    url = f"http://{ip}:{port}/api/tags"
    
    try:
        async with httpx.AsyncClient(timeout=timeout) as client:
            response = await client.get(url)
            response.raise_for_status()
            data = response.json()
            
            # Extrage numele modelelor
            models = [model.get("name", "") for model in data.get("models", [])]
            return [m for m in models if m]  # Filtrează string-uri goale
            
    except httpx.TimeoutException:
        raise Exception(f"Timeout la conectarea cu {ip}:{port}")
    except httpx.HTTPStatusError as e:
        raise Exception(f"Eroare HTTP {e.response.status_code} de la {ip}:{port}")
    except Exception as e:
        raise Exception(f"Eroare la obținerea modelelor de la {ip}:{port}: {str(e)}")


async def stream_chat_response(
    agent: Agent,
    messages: List[Dict[str, str]],
    callback: Optional[callable] = None
) -> Dict[str, Any]:
    """
    Trimite o cerere de chat către API-ul Ollama și procesează răspunsul în streaming
    
    Args:
        agent: Configurarea agentului AI
        messages: Lista de mesaje pentru conversație
        callback: Funcție callback opțională pentru fiecare token primit
        
    Returns:
        Dict cu textul complet și numărul de tokeni
    """
    url = f"http://{agent.url}/api/chat"
    payload = {
        "model": agent.model,
        "messages": messages,
        "stream": True,
        "options": {
            "num_predict": agent.max_tokens
        }
    }
    
    raspuns_complet = ""
    tokens_eval = None
    retry_count = 0
    current_timeout = agent.timeout
    
    while retry_count < MAX_RETRY:
        try:
            async with httpx.AsyncClient(timeout=current_timeout) as client:
                async with client.stream("POST", url, json=payload) as response:
                    response.raise_for_status()
                    
                    async for line in response.aiter_lines():
                        if not line:
                            continue
                        
                        try:
                            chunk = json.loads(line)
                            
                            # Extrage token-ul de conținut
                            if "message" in chunk and "content" in chunk["message"]:
                                token = chunk["message"]["content"]
                                raspuns_complet += token
                                
                                # Apelează callback-ul dacă există
                                if callback:
                                    await callback(token)
                            
                            # Verifică dacă răspunsul s-a terminat
                            if chunk.get("done", False):
                                tokens_eval = chunk.get("eval_count", None)
                                break
                                
                        except json.JSONDecodeError:
                            continue
                    
                    return {
                        "text": raspuns_complet,
                        "tokens": tokens_eval,
                        "success": True
                    }
                    
        except httpx.TimeoutException:
            retry_count += 1
            current_timeout *= 2
            
            if retry_count >= MAX_RETRY:
                return {
                    "text": None,
                    "tokens": None,
                    "success": False,
                    "error": f"Timeout depășit după {MAX_RETRY} încercări (ultima: {current_timeout}s)"
                }
            
            # Așteaptă înainte de retry
            await asyncio.sleep(1)
            
        except httpx.HTTPStatusError as e:
            return {
                "text": None,
                "tokens": None,
                "success": False,
                "error": f"Eroare HTTP {e.response.status_code}: {str(e)}"
            }
            
        except Exception as e:
            return {
                "text": None,
                "tokens": None,
                "success": False,
                "error": f"Eroare neașteptată: {str(e)}"
            }
    
    return {
        "text": None,
        "tokens": None,
        "success": False,
        "error": "Nu s-a putut obține răspuns"
    }


async def test_ollama_connection(ip: str, port: str = "11434", timeout: int = 5) -> Dict[str, Any]:
    """
    Testează conexiunea cu un server Ollama
    
    Returns:
        Dict cu 'success' (bool) și 'message' sau 'error'
    """
    try:
        models = await get_available_models(ip, port, timeout)
        return {
            "success": True,
            "message": f"Conexiune reușită. {len(models)} modele disponibile.",
            "models": models
        }
    except Exception as e:
        return {
            "success": False,
            "error": str(e)
        }
