"""A module for Natural Language Understanding provided by rasa_nlu"""

# retico
from retico_core.core import abstract
from retico_core.core.text import SpeechRecognitionIU
from retico_core.core.dialogue import DialogueActIU

# rasa
import sys
import os
# sys.path.append(os.environ['RASA'])
# from rasa.nlu.model import IncrementalInterpreter as Interpreter
from rasa.nlu.model import Interpreter

class RasaNLUModule(abstract.AbstractModule):
    """A standard rasa NLU module.

    Attributes:
        model_dir (str): The path to the directory of the NLU model generated by
            rasa_nlu.train.
        config_file (str): The path to the json file containing the rasa nlu
            configuration.
    """

    @staticmethod
    def name():
        return "Rasa NLU Module"

    @staticmethod
    def description():
        return "A Module providing Natural Language Understanding by rasa_nlu"

    @staticmethod
    def input_ius():
        return [SpeechRecognitionIU]

    @staticmethod
    def output_iu():
        return DialogueActIU

    def __init__(self, model_dir, incremental=True, **kwargs):
        """Initializes the RasaNLUModule.

        Args:
            model_dir (str): The path to the directory of the NLU model
                generated by rasa_nlu.train.
        """
        super().__init__(**kwargs)
        self.model_dir = model_dir
        self.interpreter = None
        self.incremental = incremental
        self.lb_hypotheses = []
        self.cache = None
        self.started_prediction = False
        self.interpreter = Interpreter.load(self.model_dir)
        self.prefix = []
    
    def new_utterance(self):
        if self.incremental:
            self.interpreter.new_utterance()
        self.prefix = []
        super().new_utterance()

    def process_result(self, result, input_iu, iu_type):
        #print("RESULT: {}".format(result))
        payload = {}
        for entity in result.get("entities"):
            payload[entity["entity"]] = entity["value"]
            # concepts['{}_confidence'.format(entity["entity"])] = entity['confidence']
        act = result["intent"]["name"]
        # confidence = result["intent"]["confidence"]
        # print('nlu', act, concepts, confidence)
        output_iu = self.create_iu(input_iu)
        output_iu.set_act(payload)
        piu = output_iu.previous_iu
        print(input_iu.committed)
        if input_iu.committed:
            output_iu.committed = True
            self.started_prediction = False
        else:
            self.started_prediction = True
        output_update = abstract.UpdateMessage.from_iu(output_iu, iu_type)
        return output_update
    
    def process_update(self, update_message):
        for iu,um in update_message:
            if um == abstract.UpdateType.ADD:
                update = self.process_iu(iu)
            elif um == abstract.UpdateType.REVOKE:
                update = self.process_revoke(iu)
        return update

    def process_iu(self, input_iu):
        if self.incremental:
            result = None
            for word in input_iu.get_text().split():
                text_iu = (word, "add") # only handling add for now
                result = self.interpreter.parse_incremental(text_iu)
        else:
            self.prefix.append(input_iu.get_text())
            text = ' '.join(self.prefix)
            result = self.interpreter.parse(text)
        
        if result is not None:
            p_result = self.process_result(result, input_iu, "add")
            return p_result
        

    def process_revoke(self, revoked_iu):
        
        result =  None
        if self.incremental:
            for word in reversed(revoked_iu.get_text().split()):
                text_iu = (word, "revoke") 
                # print('nlu revoke({})'.format(word))
                result = self.interpreter.parse_incremental(text_iu)
            if result is not None:
                result = self.process_result(result, revoked_iu, "revoke")
        else:
            if len(self.prefix) > 0:
                self.prefix.pop()
            
        if len(self._iu_stack) > 0:
            last_output_iu = self._iu_stack.pop()
            self.revoke(last_output_iu)
        
        return result

    def setup(self):
        print("NLU!!!!!!")
        pass


