
"""
Gestionare conversații multi-AI
Coordonează rundele, agenții și istoricul
"""
import asyncio
import uuid
from typing import Dict, List, Optional, Any
from datetime import datetime
from .models import (
    ConversationConfig, 
    ConversationState, 
    Message, 
    StreamMessage,
    Agent
)
from .ollama_service import (
    construieste_mesaje,
    INTREBARE_IMPLICITA
)
from .mock_ollama import enhanced_stream_chat_response
from .utils import (
    extrage_fraze_idei,
    save_conversation_txt,
    save_conversation_docx,
    save_conversation_json
)
from .database import ConversationDB


class ConversationManager:
    """
    Manager pentru o conversație multi-AI
    Gestionează starea, rundele și comunicarea cu agenții
    """
    
    def __init__(self, config: ConversationConfig):
        self.config = config
        self.state = ConversationState(
            id=str(uuid.uuid4()),
            config=config,
            mesaje=[],
            registry_idei={},
            is_running=False
        )
        self.conversatie_history: List[Dict[str, str]] = []
        self._stop_requested = False
        
        # Create database entry for this conversation
        self._create_database_entry()
    
    def _create_database_entry(self):
        """Creează intrarea în baza de date pentru conversație"""
        try:
            # Preparează datele agenților pentru baza de date
            agenti_data = []
            for agent in self.config.agenti:
                agenti_data.append({
                    "ip": agent.ip,
                    "port": agent.port,
                    "rol": agent.rol,
                    "model": agent.model,
                    "max_tokens": agent.max_tokens,
                    "timeout": agent.timeout
                })
            
            # Preparează configurația pentru salvare
            config_dict = {
                "subiect": self.config.subiect,
                "numar_runde": self.config.numar_runde,
                "pauza_intre_runde": self.config.pauza_intre_runde,
                "agenti": agenti_data
            }
            
            # Creează intrarea în baza de date
            ConversationDB.create_conversation(
                conversation_id=self.state.id,
                subiect=self.config.subiect,
                numar_runde=self.config.numar_runde,
                agenti=agenti_data,
                config=config_dict
            )
            
        except Exception as e:
            print(f"Error creating database entry: {e}")
    
    def _save_message_to_db(self, message: Message, runda: int):
        """Salvează un mesaj în baza de date"""
        try:
            ConversationDB.add_message(
                conversation_id=self.state.id,
                runda=runda,
                agent_url=message.agent_url,
                agent_role=message.agent_role,
                content=message.content,
                tokens=message.tokens,
                idei_noi=message.idei_noi
            )
        except Exception as e:
            print(f"Error saving message to database: {e}")
    
    def _complete_conversation_in_db(self):
        """Marchează conversația ca fiind finalizată în baza de date"""
        try:
            ConversationDB.complete_conversation(
                conversation_id=self.state.id,
                total_idei_unice=len(self.state.registry_idei)
            )
        except Exception as e:
            print(f"Error completing conversation in database: {e}")
    
    async def start(self, websocket_callback: Optional[callable] = None):
        """
        Pornește conversația și o execută până la finalizare
        
        Args:
            websocket_callback: Funcție callback pentru trimitere mesaje prin WebSocket
        """
        self.state.is_running = True
        self.state.start_time = datetime.now()
        self._stop_requested = False
        
        try:
            for runda in range(1, self.config.numar_runde + 1):
                if self._stop_requested:
                    break
                
                self.state.runda_curenta = runda
                
                # Notifică început rundă
                if websocket_callback:
                    await websocket_callback(StreamMessage(
                        type="round_start",
                        data={"round": runda, "total_rounds": self.config.numar_runde}
                    ))
                
                # Procesează fiecare agent în ordine
                for agent in self.config.agenti:
                    if self._stop_requested:
                        break
                    
                    # Obține răspunsul de la agent
                    await self._process_agent_response(agent, websocket_callback)
                
                # Notifică sfârșit rundă
                if websocket_callback:
                    await websocket_callback(StreamMessage(
                        type="round_end",
                        data={
                            "round": runda,
                            "total_ideas": len(self.state.registry_idei)
                        }
                    ))
                
                # Pauză între runde (dacă nu e ultima rundă)
                if runda < self.config.numar_runde and not self._stop_requested:
                    await asyncio.sleep(self.config.pauza_intre_runde)
            
            # Conversație finalizată
            self.state.end_time = datetime.now()
            self.state.is_running = False
            
            # Marchează conversația ca finalizată în baza de date
            self._complete_conversation_in_db()
            
            if websocket_callback:
                await websocket_callback(StreamMessage(
                    type="conversation_end",
                    data={
                        "total_rounds": self.state.runda_curenta,
                        "total_messages": len(self.state.mesaje),
                        "total_ideas": len(self.state.registry_idei),
                        "stopped_manually": self._stop_requested
                    }
                ))
            
        except Exception as e:
            self.state.is_running = False
            if websocket_callback:
                await websocket_callback(StreamMessage(
                    type="error",
                    data={"message": f"Eroare în conversație: {str(e)}"}
                ))
            raise
    
    async def _process_agent_response(self, agent: Agent, websocket_callback: Optional[callable] = None):
        """
        Procesează răspunsul unui agent
        """
        # Construiește mesajele pentru agent
        idei_list = list(self.state.registry_idei.keys())
        mesaje = construieste_mesaje(
            self.conversatie_history,
            self.config.subiect,
            agent.rol,
            agent.max_tokens,
            idei_list
        )
        
        # Buffer pentru colectare token-uri în streaming
        token_buffer = []
        
        async def token_callback(token: str):
            """Callback pentru fiecare token primit"""
            token_buffer.append(token)
            
            # Trimite token prin WebSocket
            if websocket_callback:
                await websocket_callback(StreamMessage(
                    type="token",
                    data={
                        "token": token,
                        "agent_url": agent.url,
                        "agent_role": agent.rol
                    }
                ))
        
        # Obține răspunsul de la agent (cu fallback la mock)
        rezultat = await enhanced_stream_chat_response(agent, mesaje, token_callback)
        
        if not rezultat["success"] or rezultat["text"] is None:
            # Eroare la obținerea răspunsului
            error_msg = rezultat.get("error", "Eroare necunoscută")
            
            if websocket_callback:
                await websocket_callback(StreamMessage(
                    type="error",
                    data={
                        "message": f"Eroare de la {agent.url}: {error_msg}",
                        "agent_url": agent.url,
                        "agent_role": agent.rol
                    }
                ))
            
            return
        
        text = rezultat["text"]
        tokens = rezultat["tokens"]
        
        # Extrage și înregistrează idei noi
        fraze = extrage_fraze_idei(text)
        idei_noi_count = 0
        
        for fraza in fraze:
            if fraza not in self.state.registry_idei:
                self.state.registry_idei[fraza] = True
                idei_noi_count += 1
        
        # Creează mesajul
        message = Message(
            rol="assistant",
            content=text,
            timestamp=datetime.now(),
            agent_url=agent.url,
            agent_role=agent.rol,
            tokens=tokens,
            idei_noi=idei_noi_count
        )
        
        self.state.mesaje.append(message)
        
        # Salvează mesajul în baza de date
        self._save_message_to_db(message, self.state.runda_curenta)
        
        # Adaugă în istoricul conversației
        self.conversatie_history.append({"role": "assistant", "content": text})
        self.conversatie_history.append({"role": "user", "content": INTREBARE_IMPLICITA})
        
        # Notifică mesaj complet
        if websocket_callback:
            await websocket_callback(StreamMessage(
                type="message",
                data={
                    "content": text,
                    "agent_url": agent.url,
                    "agent_role": agent.rol,
                    "tokens": tokens,
                    "idei_noi": idei_noi_count,
                    "timestamp": message.timestamp.isoformat()
                }
            ))
    
    def stop(self):
        """Oprește conversația"""
        self._stop_requested = True
        self.state.is_running = False
        self.state.end_time = datetime.now()
        
        # Marchează conversația ca finalizată în baza de date
        self._complete_conversation_in_db()
    
    def save(self, formats: List[str] = ["txt", "docx", "json"]) -> Dict[str, str]:
        """
        Salvează conversația în formatele specificate
        
        Args:
            formats: Lista de formate (txt, docx, json)
            
        Returns:
            Dict cu căile fișierelor salvate pentru fiecare format
        """
        conversation_data = self._prepare_conversation_data()
        saved_files = {}
        
        filename = None  # Va fi generat automat
        
        if "json" in formats:
            saved_files["json"] = save_conversation_json(conversation_data, filename)
        
        if "txt" in formats:
            saved_files["txt"] = save_conversation_txt(conversation_data, filename)
        
        if "docx" in formats:
            saved_files["docx"] = save_conversation_docx(conversation_data, filename)
        
        return saved_files
    
    def _prepare_conversation_data(self) -> dict:
        """
        Pregătește datele conversației pentru salvare
        """
        # Grupează mesajele pe runde
        messages_with_rounds = []
        current_round = 1
        messages_per_round = len(self.config.agenti)
        
        for i in range(0, len(self.state.mesaje), messages_per_round):
            messages_with_rounds.append({
                "type": "round_start",
                "round": current_round
            })
            
            for j in range(messages_per_round):
                if i + j < len(self.state.mesaje):
                    msg = self.state.mesaje[i + j]
                    messages_with_rounds.append({
                        "type": "message",
                        "timestamp": msg.timestamp.strftime("%Y-%m-%d %H:%M:%S"),
                        "agent_url": msg.agent_url,
                        "agent_role": msg.agent_role,
                        "content": msg.content,
                        "tokens": msg.tokens,
                        "idei_noi": msg.idei_noi
                    })
            
            current_round += 1
        
        return {
            "id": self.state.id,
            "subiect": self.config.subiect,
            "start_time": self.state.start_time.isoformat() if self.state.start_time else None,
            "end_time": self.state.end_time.isoformat() if self.state.end_time else None,
            "numar_runde": self.config.numar_runde,
            "agenti": [
                {
                    "url": agent.url,
                    "rol": agent.rol,
                    "model": agent.model,
                    "max_tokens": agent.max_tokens
                }
                for agent in self.config.agenti
            ],
            "mesaje": messages_with_rounds,
            "total_mesaje": len(self.state.mesaje),
            "total_idei_unice": len(self.state.registry_idei)
        }
    
    def get_state(self) -> ConversationState:
        """Returnează starea curentă a conversației"""
        return self.state


# Manager global pentru conversații active
_active_conversations: Dict[str, ConversationManager] = {}


def create_conversation(config: ConversationConfig) -> ConversationManager:
    """Creează și înregistrează o conversație nouă"""
    manager = ConversationManager(config)
    _active_conversations[manager.state.id] = manager
    return manager


def get_conversation(conversation_id: str) -> Optional[ConversationManager]:
    """Obține un manager de conversație după ID"""
    return _active_conversations.get(conversation_id)


def remove_conversation(conversation_id: str):
    """Elimină un manager de conversație din listă"""
    if conversation_id in _active_conversations:
        del _active_conversations[conversation_id]


def get_all_conversations() -> List[ConversationManager]:
    """Returnează toate conversațiile active"""
    return list(_active_conversations.values())
