"""
Sistema de memória de conversação
"""
import sqlite3
import json
import hashlib
from datetime import datetime
from typing import List, Dict, Optional
import asyncio
from dataclasses import dataclass

from config.settings import settings, MemoryConfig


@dataclass
class Message:
    """Representa uma mensagem"""
    role: str
    content: str
    timestamp: datetime
    metadata: Optional[Dict] = None


class ConversationMemory:
    """
    Gerencia memória de conversas com SQLite
    Suporta: histórico curto, resumos, e persistência
    """
    
    def __init__(self, config: MemoryConfig):
        self.config = config
        self.db_path = "chatbot_memory.db"
        self._init_db()
    
    def _init_db(self):
        """Inicializa o banco de dados"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS conversations (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                session_id TEXT NOT NULL,
                role TEXT NOT NULL,
                content TEXT NOT NULL,
                timestamp TEXT NOT NULL,
                summary TEXT,
                metadata TEXT
            )
        """)
        
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_session 
            ON conversations(session_id, timestamp)
        """)
        
        conn.commit()
        conn.close()
    
    async def add_message(
        self, 
        session_id: str, 
        role: str, 
        content: str,
        metadata: Optional[Dict] = None
    ):
        """Adiciona uma mensagem à memória"""
        # Executar em thread separada para não bloquear
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None, 
            self._insert_message,
            session_id, role, content, metadata
        )
        
        # Verificar se precisa resumir
        count = await self._get_message_count(session_id)
        if count > self.config.summary_threshold:
            await self._summarize_old_messages(session_id)
    
    def _insert_message(self, session_id, role, content, metadata):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute("""
            INSERT INTO conversations 
            (session_id, role, content, timestamp, metadata)
            VALUES (?, ?, ?, ?, ?)
        """, (
            session_id,
            role,
            content,
            datetime.now().isoformat(),
            json.dumps(metadata) if metadata else None
        ))
        
        conn.commit()
        conn.close()
    
    async def get_history(
        self, 
        session_id: str, 
        limit: Optional[int] = None
    ) -> List[Dict]:
        """Recupera histórico de conversa"""
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(
            None,
            self._fetch_history,
            session_id,
            limit or self.config.max_history
        )
    
    def _fetch_history(self, session_id: str, limit: int) -> List[Dict]:
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # Buscar mensagens recentes + resumos
        cursor.execute("""
            SELECT role, content, timestamp, summary 
            FROM conversations 
            WHERE session_id = ?
            ORDER BY timestamp DESC
            LIMIT ?
        """, (session_id, limit * 2))
        
        rows = cursor.fetchall()
        conn.close()
        
        # Processar: resumos primeiro, depois mensagens detalhadas
        messages = []
        for row in reversed(rows):
            role, content, timestamp, summary = row
            if summary:
                messages.append({
                    "role": "system",
                    "content": f"[Resumo anterior]: {summary}",
                    "timestamp": timestamp
                })
            else:
                messages.append({
                    "role": role,
                    "content": content,
                    "timestamp": timestamp
                })
        
        # Pegar apenas as mais recentes até o limite
        return messages[-limit:]
    
    async def _get_message_count(self, session_id: str) -> int:
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(
            None, self._count_messages, session_id
        )
    
    def _count_messages(self, session_id: str) -> int:
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute(
            "SELECT COUNT(*) FROM conversations WHERE session_id = ?",
            (session_id,)
        )
        count = cursor.fetchone()[0]
        conn.close()
        return count
    
    async def _summarize_old_messages(self, session_id: str):
        """Resume mensagens antigas para economizar tokens"""
        # Implementação simplificada - na prática, usaria LLM
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None, self._mark_summary, session_id
        )
    
    def _mark_summary(self, session_id: str):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # Pegar mensagens antigas para resumir
        cursor.execute("""
            SELECT id, content FROM conversations 
            WHERE session_id = ? AND summary IS NULL
            ORDER BY timestamp ASC
            LIMIT 10
        """, (session_id,))
        
        old_messages = cursor.fetchall()
        
        if len(old_messages) > 5:
            # Criar resumo simples (na versão completa, usar LLM)
            summary = f"Conversa com {len(old_messages)} mensagens anteriores."
            
            # Marcar como resumidas
            ids = [str(m[0]) for m in old_messages[:-2]]  # Manter últimas 2
            cursor.execute(f"""
                UPDATE conversations 
                SET summary = ?, content = '[Resumido]'
                WHERE id IN ({','.join(ids)})
            """, (summary,))
            
            conn.commit()
        
        conn.close()
    
    async def clear_history(self, session_id: str):
        """Limpa histórico de uma sessão"""
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(None, self._delete_history, session_id)
    
    def _delete_history(self, session_id: str):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute(
            "DELETE FROM conversations WHERE session_id = ?",
            (session_id,)
        )
        conn.commit()
        conn.close()
    
    async def get_all_sessions(self) -> List[str]:
        """Lista todas as sessões ativas"""
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(None, self._fetch_sessions)
    
    def _fetch_sessions(self) -> List[str]:
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute(
            "SELECT DISTINCT session_id FROM conversations ORDER BY session_id"
        )
        sessions = [row[0] for row in cursor.fetchall()]
        conn.close()
        return sessions