# data_confirmation/data_confirmation.py
from functools import lru_cache
from importlib import resources
from langchain.tools import tool
from agent.base.base_stage import BaseAgent
import copy
#from Levenshtein import distance

#def levenshtein_similarity(str1: str, str2: str) -> float:
#    s1, s2 = str1.strip().lower(), str2.strip().lower()
#    dist = distance(s1, s2)
#    max_len = max(len(s1), len(s2))
#    if max_len == 0:
#        return 100.0
#    return (1 - dist / max_len) * 100

class AuthState:
    def __init__(self, expected_cpf,
                  #expected_mother,
                  expected_birth):
        self.cpf_last_3_digits = None
        #self.mother_full_name = None
        self.birth_date_YYYY_MM_DD = None

        self.expected_cpf_last_3_digits = expected_cpf
        #self.expected_mother_full_name = expected_mother
        self.expected_birth_date_YYYY_MM_DD = expected_birth

        self.validated_target_customer = False
        self.validated_cpf = False
        #self.validated_mother_name = False
        self.validated_birth_date = False

        self.attempt_customer = 0
        self.attempt_cpf = 0
        self.attempt_birth_date = 0
        #self.attempt_mother_name = 0

        self.end_conversation = False
        
        self._saved_state = None
        self.save_state()
    @property
    def is_authenticated(self):
        return (
            self.validated_target_customer and
            (self.validated_cpf or self.validated_birth_date) 
            #and self.validated_mother_name
        )

    @property
    def attempts_exceeded(self):
        """Retorna True se qualquer tentativa for maior que 2."""
        return any([
            self.attempt_customer >= 3,
            self.attempt_cpf >= 3,
            self.attempt_birth_date >= 3,
            #self.attempt_mother_name >= 3,
        ])
    
    def save_state(self):
        self._saved_state = copy.deepcopy(self.__dict__)
        self._saved_state.pop("_saved_state", None)

    def restore_state(self):
        if self._saved_state is None:
            raise RuntimeError("Nenhum estado foi salvo ainda.")

        self.__dict__.update(copy.deepcopy(self._saved_state))

class DataConfirmationAgent(BaseAgent):
    def __init__(
        self,
        expected_cpf_last_3,
        #expected_mother,
        expected_birth_date,
        streaming=False,
        prompt_vars = None
    ):

        self.state = AuthState(expected_cpf_last_3,
                            #expected_mother,
                            expected_birth_date)
        tools = self._build_tools()
        super().__init__(
            tools=tools,
            streaming=streaming,
            prompt_vars=prompt_vars,
            agent_name='data_confirmation'
        )

    @lru_cache
    def _load_prompt(self) -> str:
        prompt_text = resources.files("agent.prompts").joinpath("data_confirmation.txt").read_text(encoding="utf-8")
        general_rules = resources.files("agent.prompts").joinpath("general_rules.txt").read_text(encoding="utf-8")
        return prompt_text.replace("{general_rules}", general_rules)

    # ----------------- TOOLS -----------------
    def _build_tools(self):
        @tool
        def detect_name_target_customer(is_target_customer: bool):
            """Confirma se o interlocutor é o cliente alvo. Chame após o cliente responder à pergunta de confirmação de nome.
is_target_customer=true: cliente confirmou dizendo 'eu confirmo'
is_target_customer=false: cliente negou ou informou outro nome"""
            self.state.validated_target_customer = is_target_customer
            self.state.attempt_customer += 1
            return is_target_customer

        #@tool
        #def check_full_mother_name(name: str):
        #    """Captura o nome completo da mãe dito pelo cliente. Chame sempre que responder a pergunta sobre o nome da mãe."""
        #    self.state.mother_full_name = name
        #    self.state.attempt_mother_name += 1
        #    self.state.validated_mother_name = True if levenshtein_similarity(name, self.state.expected_mother_full_name) > 80 else False
        #    return "correct" if self.state.validated_mother_name else "incorrect"

        @tool
        def check_birth_date(date_YYYY_MM_DD: str):
            """Recebe a data de nascimento informada pelo cliente no formato YYYY-MM-DD. Converta datas por extenso para o formato antes de chamar (ex: '1 de janeiro de 2000' → '2000-01-01')."""
            print(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. Diga apenas ###end_data_confirmation###" if self.state.validated_birth_date else "incorrect"

        @tool
        def check_cpf_digits(digits: str):
            """Recebe os dígitos do CPF informados pelo cliente como string numérica. Converta números por extenso para dígitos antes de chamar (ex: 'um dois meia seis' → '1266'). Envie todos os dígitos ditos, mesmo que mais de 3."""
            print(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. Diga apenas ###end_data_confirmation###" if self.state.validated_cpf else "incorrect"

        @tool
        def purchase_cancellation(end: bool):
            """Encerra a chamada quando o cliente desistir claramente da compra. Chame com end=true."""
            print(">>>>",end)
            self.state.end_conversation = end
            return end
    
        return [detect_name_target_customer, check_birth_date, check_cpf_digits, purchase_cancellation]# , check_full_mother_name

    def set_interruption_message(self, text: str):
        if self.messages:
            self.messages[-1].content = f"{text}"
            
    def run_confirmation(self, user_input: str):
        self.state.save_state()
        result = self.run(user_input.replace('.','').replace('-','').replace('/',''))

        return result