"""
Analyzer - Motor de análise da Tiramisu
Integra RAG + GPT-5 + Processo das 3 Árvores
"""
import sys
import os
from typing import List, Tuple, Dict

# Adicionar path do projeto
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))

from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.schema import Document

from config import settings
from tiramisu.models.schemas import AnalysisType, ThreeTreesAnalysis, TriadInsights, Proposal, AnalysisResponse
from tiramisu.engine.prompts import get_analysis_prompt, RAG_SEARCH_PROMPT

from tiramisu.engine.response_formatter import format_consultation_response, format_planning_response

class TiramisuAnalyzer:
    """
    Motor de análise da Tiramisu
    """
    
    def __init__(self, conversation_id: str = None):
        """Inicializa o analyzer com suporte a conversas"""
        self.embeddings = OpenAIEmbeddings(
            model=settings.EMBEDDING_MODEL,
            openai_api_key=settings.OPENAI_API_KEY
        )
        
        # Carregar vector store
        self.vector_store = self._load_vector_store()
        
        # Inicializar GPT-5
        self.llm = ChatOpenAI(
            model="gpt-5",
            openai_api_key=settings.OPENAI_API_KEY
        )
        
        # Conversation Manager
        from tiramisu.engine.conversation_manager import ConversationManager
        self.conversation_manager = ConversationManager()
        self.conversation_id = conversation_id
        
        print("✅ Analyzer inicializado com suporte a conversas")
    
    def _load_vector_store(self) -> FAISS:
        """Carrega o vector store FAISS"""
        try:
            vector_store = FAISS.load_local(
                str(settings.FAISS_INDEX_DIR),
                self.embeddings,
                allow_dangerous_deserialization=True
            )
            print("✅ Vector store carregado com sucesso")
            return vector_store
        except Exception as e:
            print(f"❌ Erro ao carregar vector store: {e}")
            raise
    
    def _expand_query(self, query: str, analysis_type: str = None) -> List[str]:
        """
        Expande a query com sinônimos e termos relacionados
        usando o LLM para gerar variações semânticas
        """
        # Mapeamento manual para termos comuns (rápido)
        expansions = {
            "vendas": ["conversão", "receita", "MRR", "ARR", "faturamento", "comercial"],
            "marketing": ["publicidade", "propaganda", "divulgação", "promoção", "branding"],
            "conteúdo": ["copy", "texto", "redação", "storytelling", "narrativa"],
            "digital": ["online", "internet", "web", "redes sociais", "social media"],
            "estratégia": ["planejamento", "tática", "posicionamento", "plano"],
            "cliente": ["consumidor", "comprador", "público", "audiência", "lead"],
            "conversão": ["vendas", "fechamento", "aquisição", "CRO", "taxa de conversão"]
        }
        
        # Query original sempre primeiro
        expanded = [query]
        
        # Adicionar sinônimos conhecidos
        query_lower = query.lower()
        for termo, sinonimos in expansions.items():
            if termo in query_lower:
                # Substituir termo por sinônimos
                for sinonimo in sinonimos[:2]:  # Limitar a 2 sinônimos
                    expanded_query = query_lower.replace(termo, sinonimo)
                    expanded.append(expanded_query)
        
        # Se for tipo de análise específico, adicionar contexto
        if analysis_type:
            context_query = f"{analysis_type} {query}"
            expanded.append(context_query)
        
        # Limitar a 4 variações para não sobrecarregar
        return expanded[:4]
    def _search_rag_knowledge(self, analysis_type: str, content: str, context: str = None) -> Tuple[str, List[str]]:
        """
        Busca conhecimento relevante no RAG com query expansion, re-ranking e threshold
        
        Returns:
            Tuple[str, List[str]]: (contexto_rag, fontes)
        """
        # Criar query de busca
        search_query = f"{analysis_type}: {content[:200]}"
        if context:
            search_query += f" {context[:100]}"
        
        # QUERY EXPANSION - Expandir termos
        expanded_queries = self._expand_query(search_query, analysis_type)
        
        print(f"🔍 Query original: {search_query[:80]}...")
        print(f"📊 Queries expandidas ({len(expanded_queries)}): {[q[:40]+'...' for q in expanded_queries]}")
        
        # Buscar com todas as variações
        all_results = []
        for query in expanded_queries:
            results = self.vector_store.similarity_search_with_score(query, k=8)
            all_results.extend(results)
        
        # Remover duplicatas (mesmo doc.page_content)
        seen_content = set()
        unique_results = []
        for doc, score in all_results:
            content_hash = hash(doc.page_content[:200])
            if content_hash not in seen_content:
                seen_content.add(content_hash)
                unique_results.append((doc, score))
        
        # Filtra por threshold (FAISS usa distância, menor = melhor)
        filtered_results = [
            (doc, score) for doc, score in unique_results 
            if score <= 0.5  # Só aceita alta relevância
        ]
        
        # Se filtro muito restritivo, pega top 5
        if not filtered_results:
            filtered_results = unique_results[:5]
        
        # Re-ranking: ordena e pega top 5
        sorted_results = sorted(filtered_results, key=lambda x: x[1])
        top_results = sorted_results[:5]
        
        # Monta contexto com metadados ENRIQUECIDOS
        rag_context_parts = []
        for doc, score in top_results:
            source = doc.metadata.get('source', 'Desconhecido')
            author = doc.metadata.get('author', 'Desconhecido')
            relevance = 1 - score  # Converter distância em relevância
            
            rag_context_parts.append(
                f"📚 Fonte: {source} ({author}) - Relevância: {relevance:.2f}\n"
                f"{doc.page_content[:500]}..."
            )
        
        rag_context = "\n\n".join(rag_context_parts)
        
        # Extrair fontes únicas
        sources = list(set([
            doc.metadata.get('source', 'Desconhecido') 
            for doc, _ in top_results
        ]))
        
        # Logs para debug
        print(f"✅ Encontrados {len(unique_results)} chunks únicos de {len(all_results)} totais")
        print(f"✅ Filtrados {len(filtered_results)} chunks relevantes (threshold <= 0.5)")
        print(f"📊 Usando top {len(top_results)} chunks para análise")
        
        return rag_context, sources
        """
        Parseia a resposta do GPT-5 e extrai as seções
        """
        sections = {
            'summary': '',
            'roots': '',
            'trunk': '',
            'branches': '',
            'kotler': '',
            'gary_vee': '',
            'martha': '',
            'improved_version': '',
            'action_plan': [],
            'key_recommendations': [],
            'expected_results': ''
        }
        
        # Parsing simplificado (você pode melhorar isso)
        lines = response.split('\n')
        current_section = None
        current_text = []
        
        for line in lines:
            line_lower = line.lower()
            
            # Detectar seções
            if 'resumo executivo' in line_lower or 'summary' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'summary'
                current_text = []
            elif 'raízes' in line_lower or 'roots' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'roots'
                current_text = []
            elif 'tronco' in line_lower or 'trunk' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'trunk'
                current_text = []
            elif 'galhos' in line_lower or 'branches' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'branches'
                current_text = []
            elif 'kotler' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'kotler'
                current_text = []
            elif 'gary' in line_lower or 'vee' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'gary_vee'
                current_text = []
            elif 'martha' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'martha'
                current_text = []
            elif 'versão melhorada' in line_lower or 'improved version' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'improved_version'
                current_text = []
            elif 'plano de ação' in line_lower or 'action plan' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'action_plan'
                current_text = []
            elif 'recomendações' in line_lower or 'recommendations' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'key_recommendations'
                current_text = []
            elif 'resultados esperados' in line_lower or 'expected results' in line_lower:
                if current_section:
                    sections[current_section] = '\n'.join(current_text).strip()
                current_section = 'expected_results'
                current_text = []
            else:
                if current_section:
                    current_text.append(line)
        
        # Salvar última seção
        if current_section:
            sections[current_section] = '\n'.join(current_text).strip()
        
        # Processar listas
        if sections['action_plan']:
            sections['action_plan'] = [
                line.strip('- ').strip() 
                for line in sections['action_plan'].split('\n') 
                if line.strip() and line.strip().startswith('-')
            ]
        
        if sections['key_recommendations']:
            sections['key_recommendations'] = [
                line.strip('- ').strip() 
                for line in sections['key_recommendations'].split('\n') 
                if line.strip() and line.strip().startswith('-')
            ]
        
        # Fallbacks
        if not sections['action_plan']:
            sections['action_plan'] = ['Análise em andamento - detalhes na resposta completa']
        
        if not sections['key_recommendations']:
            sections['key_recommendations'] = ['Veja análise completa para recomendações']
        
        if not sections['summary']:
            sections['summary'] = response[:200] + '...'
        
        return sections
    

    def _parse_gpt_response(self, gpt_response: str) -> dict:
        """Parseia a resposta estruturada do GPT-5"""
        import re
        
        text = str(gpt_response) if gpt_response else ""
        result = {
            'summary': '', 'roots': '', 'trunk': '', 'branches': '',
            'kotler': '', 'gary_vee': '', 'martha': '',
            'improved_version': '', 'action_plan': '',
            'key_recommendations': '', 'expected_results': ''
        }
        
        try:
            m = re.search(r'1\)\s*RESUMO EXECUTIVO\s*\n(.*?)(?=\n2\)|$)', text, re.DOTALL | re.I)
            if m: result['summary'] = m.group(1).strip()[:5000]
            
            m = re.search(r'🌱\s*RAÍZES.*?\n(.*?)(?=🌲|$)', text, re.DOTALL | re.I)
            if m: result['roots'] = m.group(1).strip()[:5000]
            
            m = re.search(r'🌲\s*TRONCO.*?\n(.*?)(?=🍃|$)', text, re.DOTALL | re.I)
            if m: result['trunk'] = m.group(1).strip()[:5000]
            
            m = re.search(r'🍃\s*GALHOS.*?\n(.*?)(?=3\)|$)', text, re.DOTALL | re.I)
            if m: result['branches'] = m.group(1).strip()[:5000]
            
            m = re.search(r'🎓\s*KOTLER.*?\n(.*?)(?=🔥|$)', text, re.DOTALL | re.I)
            if m: result['kotler'] = m.group(1).strip()[:5000]
            
            m = re.search(r'🔥\s*GARY.*?\n(.*?)(?=🤖|$)', text, re.DOTALL | re.I)
            if m: result['gary_vee'] = m.group(1).strip()[:5000]
            
            m = re.search(r'🤖\s*MARTHA.*?\n(.*?)(?=4\)|$)', text, re.DOTALL | re.I)
            if m: result['martha'] = m.group(1).strip()[:5000]
            
            m = re.search(r'Versão melhorada.*?\n(.*?)(?=Objetivos|$)', text, re.DOTALL | re.I)
            if m: result['improved_version'] = m.group(1).strip()[:15000]
            
            m = re.search(r'Canais e táticas.*?\n(.*?)(?=Budget|KPIs|Timeline|$)', text, re.DOTALL | re.I)
            if m: result['action_plan'] = m.group(1).strip()[:10000]
            
            m = re.search(r'KPIs e métricas.*?\n(.*?)(?=Timeline|Riscos|$)', text, re.DOTALL | re.I)
            if m: result['key_recommendations'] = m.group(1).strip()[:15000]
            
            m = re.search(r'Resultados esperados.*?\n(.*?)(?=Amarração|$)', text, re.DOTALL | re.I)
            if m: result['expected_results'] = m.group(1).strip()[:5000]
            
            if result['action_plan'] and isinstance(result['action_plan'], str):
                lines = [l.strip() for l in result['action_plan'].split('\n') if l.strip()]
                bullets = [l for l in lines if l.startswith('-') or l.startswith('•')]
                result['action_plan'] = bullets[:10] if bullets else [result['action_plan'][:200]]
            
            if result['key_recommendations'] and isinstance(result['key_recommendations'], str):
                lines = [l.strip() for l in result['key_recommendations'].split('\n') if l.strip()]
                bullets = [l for l in lines if l.startswith('-') or l.startswith('•')]
                result['key_recommendations'] = bullets[:10] if bullets else [result['key_recommendations'][:200]]
            
            if not result['summary']: result['summary'] = text[:300] or 'Análise processada'
            if not result['roots']: result['roots'] = 'Diagnóstico na análise'
            if not result['trunk']: result['trunk'] = 'Estratégia definida'
            if not result['branches']: result['branches'] = 'Táticas detalhadas'
            if not result['kotler']: result['kotler'] = 'Insights estratégicos'
            if not result['gary_vee']: result['gary_vee'] = 'Execução definida'
            if not result['martha']: result['martha'] = 'Tecnologia integrada'
            if not result['improved_version']: result['improved_version'] = result['summary']
            if not result['action_plan']: result['action_plan'] = ['Plano detalhado']
            if not result['key_recommendations']: result['key_recommendations'] = ['Recomendações fornecidas']
            if not result['expected_results']: result['expected_results'] = 'Resultados mapeados'
                
        except Exception as e:
            self.logger.error(f"Erro parse GPT: {e}")
        
        return result


    def analyze(
        self, 
        analysis_type: AnalysisType, 
        content: str, 
        context: str = None
    ) -> AnalysisResponse:
        """
        Executa análise completa
        
        Args:
            analysis_type: Tipo de análise
            content: Conteúdo a analisar
            context: Contexto adicional (opcional)
            
        Returns:
            AnalysisResponse: Análise completa estruturada
        """
        print(f"\n🍰 TIRAMISU iniciando análise: {analysis_type}")
        
        # 1. Buscar conhecimento no RAG
        print("�� Buscando conhecimento dos 3 autores...")
        rag_context, sources = self._search_rag_knowledge(
            analysis_type.value, 
            content, 
            context
        )
        
        # 2. Gerar prompt completo
        print("🧠 Preparando análise com GPT-5...")
        prompt = get_analysis_prompt(
            analysis_type.value,
            content,
            context or "",
            rag_context
        )
        
        # 3. Chamar GPT-5 para análise
        print("💭 GPT-5 analisando com raciocínio estendido...")
        response = self.llm.invoke(prompt)
        gpt_response = response.content
        
        # 4. Parsear resposta
        print("📊 Estruturando análise...")
        print("\n" + "="*80)
        print("🔍 RESPOSTA RAW DO GPT-5:")
        print("="*80)
        print(gpt_response)
        print("="*80 + "\n")
        parsed = self._parse_gpt_response(gpt_response)
        
        # 5. Construir response estruturada
        analysis_response = AnalysisResponse(
            summary=parsed['summary'] or "Análise completa disponível nas seções abaixo.",
            three_trees=ThreeTreesAnalysis(
                roots=parsed['roots'] or "Diagnóstico em andamento.",
                trunk=parsed['trunk'] or "Avaliação em andamento.",
                branches=parsed['branches'] or "Propostas em elaboração."
            ),
            triad_insights=TriadInsights(
                kotler=parsed['kotler'] or "Análise estratégica em andamento.",
                gary_vee=parsed['gary_vee'] or "Análise de execução em andamento.",
                martha=parsed['martha'] or "Análise tecnológica em andamento."
            ),
            proposal=Proposal(
                improved_version=parsed['improved_version'] or None,
                action_plan=parsed['action_plan'],
                key_recommendations=parsed['key_recommendations'],
                expected_results=parsed['expected_results'] or "Resultados detalhados na análise completa."
            ),
            rag_sources=sources
        )
        
        print("✅ Análise completa!\n")
        
        return analysis_response

    def consult(self, question: str, context: str = None) -> str:
        """
        Modo Consultoria: responde perguntas livres
        """
        print(f"\n{'='*70}")
        print(f"💬 TIRAMISU - MODO CONSULTORIA")
        print(f"{'='*70}\n")
        
        # Buscar no RAG
        print("📚 Buscando conhecimento dos 3 autores...")
        rag_context, sources = self._search_rag_knowledge("consultation", question, context)
        
        # Montar prompt
        from tiramisu.engine.prompts import CONSULTATION_MODE_PROMPT
        prompt = CONSULTATION_MODE_PROMPT.format(
            question=question,
            rag_context=rag_context
        )
        
        # Chamar LLM
        print("💭 Consultando a Triade...")
        response = self.llm.invoke(prompt)
        
        print(f"\n{'='*70}")
        print("✅ CONSULTA CONCLUÍDA!")
        print(f"{'='*70}\n")
        
        return format_consultation_response(response.content, sources)
    
    def plan(self, objective: str, context: str = None) -> str:
        """
        Modo Planejamento: cria estratégia do zero
        """
        print(f"\n{'='*70}")
        print(f"📋 TIRAMISU - MODO PLANEJAMENTO")
        print(f"{'='*70}\n")
        
        # Buscar no RAG
        print("📚 Buscando frameworks dos 3 autores...")
        rag_context, sources = self._search_rag_knowledge("planning", objective, context)
        
        # Montar prompt
        from tiramisu.engine.prompts import PLANNING_MODE_PROMPT
        prompt = PLANNING_MODE_PROMPT.format(
            objective=objective,
            context=context or "Não especificado",
            rag_context=rag_context
        )
        
        # Chamar LLM
        print("🎯 Criando planejamento estratégico...")
        response = self.llm.invoke(prompt)
        
        print(f"\n{'='*70}")
        print("✅ PLANEJAMENTO CONCLUÍDO!")
        print(f"{'='*70}\n")
        
        return format_planning_response(response.content, sources)

    # ============================================================
    # MÉTODOS DE CONVERSA CONTÍNUA
    # ============================================================
    
    def start_conversation(self, title: str = None) -> str:
        """Inicia nova conversa e retorna o ID"""
        self.conversation_id = self.conversation_manager.start_conversation(title)
        return self.conversation_id
    
    def continue_conversation(
        self, 
        user_message: str, 
        mode: str = "consult"
    ) -> str:
        """
        Continua uma conversa existente com contexto
        
        Args:
            user_message: Pergunta/refinamento do usuário
            mode: 'consult', 'plan' ou 'analyze'
        
        Returns:
            Resposta formatada com contexto da conversa
        """
        if not self.conversation_id:
            raise ValueError("Nenhuma conversa ativa. Use start_conversation() primeiro.")
        
        # Salvar mensagem do usuário
        self.conversation_manager.add_user_message(
            self.conversation_id, 
            user_message
        )
        
        # Obter contexto da conversa
        conversation_context = self.conversation_manager.get_conversation_context(
            self.conversation_id
        )
        
        print(f"\n{'='*70}")
        print(f"💬 CONTINUANDO CONVERSA (modo: {mode})")
        print(f"📜 Contexto: {len(conversation_context)} caracteres de histórico")
        print(f"{'='*70}\n")
        
        # Chamar método apropriado com contexto
        if mode == "consult":
            # Adicionar contexto da conversa à pergunta
            enriched_question = f"{conversation_context}\n\nNOVA PERGUNTA: {user_message}"
            response = self.consult(enriched_question, context=None)
            sources = []  # TODO: extrair sources do response
            
        elif mode == "plan":
            enriched_objective = f"{conversation_context}\n\nNOVO OBJETIVO: {user_message}"
            response = self.plan(enriched_objective, context=None)
            sources = []
            
        else:
            raise ValueError(f"Modo inválido: {mode}")
        
        # Salvar resposta da Tiramisu
        self.conversation_manager.add_assistant_message(
            conversation_id=self.conversation_id,
            content=response,
            mode=mode,
            sources=sources
        )
        
        return response
    
    def get_conversation_history(self) -> str:
        """Retorna histórico formatado da conversa atual"""
        if not self.conversation_id:
            return "Nenhuma conversa ativa"
        
        return self.conversation_manager.format_conversation_for_display(
            self.conversation_id
        )
    
    def list_my_conversations(self, limit: int = 20) -> List[Dict]:
        """Lista conversas recentes"""
        return self.conversation_manager.list_conversations(limit)
