# stage/unified_agent.py
from functools import lru_cache
from importlib import resources
from typing import Literal
from langchain.tools import tool
from agent.base.base_stage import BaseAgent
from agent.stage.unified_state import UnifiedState, ConversationPhase
from agent.stage.prompt_manager import PromptManager


class UnifiedAgent(BaseAgent):
    """Agente unificado que gerencia toda a conversa com prompt dinâmico."""

    def __init__(
        self,
        expected_cpf_last_3: str = "",
        expected_birth_date: str = "",
        streaming: bool = False,
        prompt_vars: dict = None,
    ):
        self.state = UnifiedState(
            expected_cpf_last_3=expected_cpf_last_3,
            expected_birth_date=expected_birth_date,
        )

        self._prompt_vars = prompt_vars or {}

        # Carrega knowledge base e adiciona às variáveis
        knowledge = PromptManager.load_knowledge_base()
        self._prompt_vars["knowledge_base"] = knowledge

        self.prompt_manager = PromptManager(self.state, self._prompt_vars)

        tools = self._build_tools()

        super().__init__(
            tools=tools,
            streaming=streaming,
            prompt_vars={},  # não usar substituição do BaseAgent — o PromptManager cuida
            agent_name="unified",
            dynamic_prompt=True,  # permite atualizar system_prompt entre chamadas
        )

    # ══════════════════════════════════════════════════════════
    # Overrides do BaseAgent
    # ══════════════════════════════════════════════════════════

    def _load_prompt(self) -> str:
        """Retorna o prompt dinâmico gerado pelo PromptManager.
        
        NOTA: este método é chamado uma vez no __init__ do BaseAgent,
        mas o prompt real é atualizado dinamicamente via _get_dynamic_prompt().
        """
        return self.prompt_manager.build_prompt()

    def _get_dynamic_prompt(self) -> str:
        """Gera o prompt atualizado a cada invocação do agente."""
        return self.prompt_manager.build_prompt()

    # ══════════════════════════════════════════════════════════
    # Tools — todas as 6 tools dos 4 estágios
    # ══════════════════════════════════════════════════════════

    def _build_tools(self):

        # ── Tool 1: Presentation ──
        @tool
        def classify_customer_response(
            response: Literal["confirmed_target_customer", "denied_target_customer", "other"]
        ):
            """Classifica a resposta do cliente na etapa de apresentação:
confirmed_target_customer: interlocutor confirmou ser o cliente alvo
denied_target_customer: interlocutor negou ser o cliente alvo
other: outro"""
            print(f"[Tool] classify_customer_response: {response}")
            self.state.name_validation_attempt += 1

            if self.state.name_validation_attempt >= 4:
                return "Finalize a conversa com uma mensagem que contenha no final 'A TIM agradece sua atenção.'"

            if response == "confirmed_target_customer":
                self.state.is_target_customer = True
                return "Cliente confirmado. Aguarde a próxima etapa."

            if response == "denied_target_customer":
                return "Finalize a conversa com uma mensagem de despedida que contenha 'A TIM agradece sua atenção.'"

            return "Lide com o input do usuario"

        # ── Tool 2: Argumentation + Formalization ──
        @tool
        def detect_intention_purchase(
            intention: Literal[
                "customer_declined_purchase",
                "customer_accepted_purchase",
                "off_topic_from_sale",
                "customer_asked_question",
                "other",
            ]
        ):
            """O agente deve chamar esta ferramenta sempre que o cliente falar algo.
- customer_declined_purchase: cliente negou a oferta
- customer_accepted_purchase: cliente aceitou comprar
- off_topic_from_sale: conversas aleatórias sem sentido
- customer_asked_question: cliente fez uma pergunta
- other: outro"""
            print(f"[Tool] detect_intention_purchase ({self.state.current_phase.value}): {intention}")

            phase = self.state.current_phase

            # ── ARGUMENTATION ──
            if phase == ConversationPhase.ARGUMENTATION:
                if intention == "customer_accepted_purchase":
                    self.state.arg_accepted_count += 1
                    if self.state.arg_accepted_count >= 2:
                        self.state.arg_accepted = True
                        return "Cliente confirmou a compra. Aguarde a próxima etapa."
                    return "Peça a segunda confirmação"

                # Reset accepted count se não for aceite
                self.state.arg_accepted_count = 0

                if intention == "customer_declined_purchase":
                    self.state.arg_declines += 1
                    if self.state.arg_declines > 2:
                        return f"{self.state.arg_declines}º recusa. Finalize a conversa com 'Tudo bem... A TIM agradece sua atenção.'"
                    return f"{self.state.arg_declines}º rejeição"

                if intention == "off_topic_from_sale":
                    self.state.arg_off_topic += 1
                    if self.state.arg_off_topic > 3:
                        return "Finalize a conversa com 'Tudo bem... A TIM agradece sua atenção.'"

                return "Lide com o input do usuario"

            # ── FORMALIZATION ──
            elif phase == ConversationPhase.FORMALIZATION:
                if intention == "customer_accepted_purchase":
                    self.state.form_accepted = True
                    return intention

                if intention == "customer_declined_purchase":
                    self.state.form_declines += 1
                    return intention

                if intention == "customer_asked_question":
                    self.state.form_questions += 1
                    return intention

                return intention

            return "Lide com o input do usuario"

        # ── Tool 3: Data Confirmation - Nome ──
        @tool
        def detect_name_target_customer(is_target_customer: bool):
            """Detecta se está falando com o cliente alvo ou não. Chame sempre que responder a pergunta se está falando com o cliente."""
            print(f"[Tool] detect_name_target_customer: {is_target_customer}")
            self.state.validated_target_customer = is_target_customer
            self.state.attempt_customer += 1
            return is_target_customer

        # ── Tool 4: Data Confirmation - CPF ──
        @tool
        def check_cpf_digits(digits: str):
            """Recebe exatamente os dígitos do CPF completo ditos pelo cliente"""
            print(f"[Tool] check_cpf_digits: {digits}")
            digits = digits[-3:]
            self.state.cpf_last_3_digits = digits
            self.state.attempt_cpf += 1
            self.state.validated_cpf = digits == self.state.expected_cpf_last_3_digits
            return "correct" if self.state.validated_cpf else "incorrect"

        # ── Tool 5: Data Confirmation - Data Nascimento ──
        @tool
        def check_birth_date(date_YYYY_MM_DD: str):
            """Captura a data de nascimento do cliente (YYYY-MM-DD)."""
            print(f"[Tool] check_birth_date: {date_YYYY_MM_DD}")
            self.state.birth_date_YYYY_MM_DD = date_YYYY_MM_DD
            self.state.attempt_birth_date += 1
            self.state.validated_birth_date = date_YYYY_MM_DD == self.state.expected_birth_date_YYYY_MM_DD
            return "correct" if self.state.validated_birth_date else "incorrect"

        # ── Tool 6: Cancelamento ──
        @tool
        def purchase_cancellation(end: bool):
            """Encerra a chamada mediante mensagem clara de desistência da compra"""
            print(f"[Tool] purchase_cancellation: {end}")
            self.state.end_conversation = end
            return end

        return [
            classify_customer_response,
            detect_intention_purchase,
            detect_name_target_customer,
            check_cpf_digits,
            check_birth_date,
            purchase_cancellation,
        ]

    # ══════════════════════════════════════════════════════════
    # Set interruption
    # ══════════════════════════════════════════════════════════

    def set_interruption_message(self, text: str):
        if self.messages:
            self.messages[-1].content = f"{text}"

    # ══════════════════════════════════════════════════════════
    # Run principal — com transição de fase
    # ══════════════════════════════════════════════════════════

    def run_unified(self, user_input: str):
        """Executa um turno da conversa e verifica transições de fase.
        
        Retorna:
            dict com keys: output, phase, auto, transition_text
            - output: resposta do agente
            - phase: fase atual após o turno
            - auto: se houve transição automática (próxima fase precisa de START)
            - transition_text: texto fixo a ser empurrado para o output quando há transição
        """
        self.state.save_state()

        # Atualiza o system prompt dinamicamente antes de rodar
        self.system_prompt = self._get_dynamic_prompt()

        # Limpa formatação de CPF/datas no input
        if self.state.current_phase == ConversationPhase.DATA_CONFIRMATION:
            user_input = user_input.replace(".", "").replace("-", "").replace("/", "")

        result = self.run(user_input)
        output = result["output"]

        # Verifica se precisa finalizar
        if "tim agradece sua atenção" in output.lower():
            self.state.end_conversation = True

        # ── Transições de fase ──
        phase = self.state.current_phase

        # Presentation → Argumentation
        if phase == ConversationPhase.PRESENTATION and self.state.is_target_customer:
            self.state.current_phase = ConversationPhase.ARGUMENTATION
            print(f"\n🔄 Transição: PRESENTATION → ARGUMENTATION")
            return {
                "output": output,
                "phase": ConversationPhase.ARGUMENTATION.value,
                "auto": True,
                "transition_text": None,  # será gerado pelo pipeline com start_message_argumentation
            }

        # Argumentation → DataConfirmation
        if phase == ConversationPhase.ARGUMENTATION and self.state.arg_accepted:
            self.state.current_phase = ConversationPhase.DATA_CONFIRMATION
            print(f"\n🔄 Transição: ARGUMENTATION → DATA_CONFIRMATION")
            return {
                "output": output,
                "phase": ConversationPhase.DATA_CONFIRMATION.value,
                "auto": True,
                "transition_text": None,  # será gerado pelo pipeline com ###START###
            }

        # DataConfirmation → Formalization
        if phase == ConversationPhase.DATA_CONFIRMATION and self.state.is_authenticated:
            self.state.current_phase = ConversationPhase.FORMALIZATION
            print(f"\n🔄 Transição: DATA_CONFIRMATION → FORMALIZATION")
            return {
                "output": output,
                "phase": ConversationPhase.FORMALIZATION.value,
                "auto": True,
                "transition_text": None,  # será gerado pelo pipeline com texto obrigatório
            }

        # Formalization → DONE (aceite)
        if phase == ConversationPhase.FORMALIZATION and self.state.form_accepted:
            self.state.current_phase = ConversationPhase.DONE
            print(f"\n✅ Transição: FORMALIZATION → DONE (aceite)")
            return {
                "output": output,
                "phase": ConversationPhase.DONE.value,
                "auto": False,
                "transition_text": None,
            }

        # Formalization → DONE (2 recusas)
        if phase == ConversationPhase.FORMALIZATION and self.state.form_declines >= 2:
            self.state.current_phase = ConversationPhase.DONE
            print(f"\n❌ Transição: FORMALIZATION → DONE (recusas)")
            return {
                "output": output,
                "phase": ConversationPhase.DONE.value,
                "auto": False,
                "transition_text": None,
            }

        # End conversation (qualquer fase)
        if self.state.end_conversation:
            self.state.current_phase = ConversationPhase.DONE
            return {
                "output": output,
                "phase": ConversationPhase.DONE.value,
                "auto": False,
                "transition_text": None,
            }

        # Sem transição — continua na mesma fase
        return {
            "output": output,
            "phase": phase.value,
            "auto": False,
            "transition_text": None,
        }
