# -*- coding: utf-8 -*-
"""
Rule-based agent.
"""

import copy
import random
import sys, os
sys.path.append(os.getcwd().replace("Flat_DQN/agent",""))

from OpenMedicalChatBox.Flat_DQN.agent import Agent
from . import dialogue_configuration


class AgentRule(Agent):
    """
    Rule-based agent.
    """
    def __init__(self, slot_set, disease_symptom, parameter):
        super(AgentRule,self).__init__(slot_set=slot_set,disease_symptom=disease_symptom,parameter=parameter)

    def next(self, state, turn, greedy_strategy, **kwargs):
        candidate_disease_symptoms = self._get_candidate_disease_symptoms(state=state)
        disease = candidate_disease_symptoms["disease"]
        candidate_symptoms = candidate_disease_symptoms["candidate_symptoms"]

        self.agent_action["request_slots"].clear()
        self.agent_action["explicit_inform_slots"].clear()
        self.agent_action["implicit_inform_slots"].clear()
        self.agent_action["inform_slots"].clear()
        self.agent_action["turn"] = turn

        if len(candidate_symptoms) == 0:
            self.agent_action["action"] = "inform"
            self.agent_action["inform_slots"]["disease"] = disease
        else:
            symptom = random.choice(candidate_symptoms)
            self.agent_action["action"] = "request"
            self.agent_action["request_slots"].clear()
            self.agent_action["request_slots"][symptom] = dialogue_configuration.VALUE_UNKNOWN
        agent_action = copy.deepcopy(self.agent_action)
        agent_action.pop("turn")
        agent_action.pop("speaker")
        agent_index = self.action_space.index(agent_action)
        return self.agent_action, agent_index

    def _get_candidate_disease_symptoms(self, state):
        """
        Comparing state["current_slots"] with disease_symptom to identify which disease the user may have.
        :param state: a dict, the current dialogue state gotten from dialogue state tracker..
        :return: a list of candidate symptoms.
        """
        
        inform_slots = state["current_slots"]["explicit_inform_slots"]
        inform_slots.update(state["current_slots"]["implicit_inform_slots"])

        # Calculate number of informed symptom for each disease.
        disease_match_number = {}
        for disease in self.disease_symptom.keys():
            disease_match_number[disease] = {}
            disease_match_number[disease]["yes"] = 0
            disease_match_number[disease]["not_sure"] = 0
            disease_match_number[disease]["deny"] = 0

        for slot in inform_slots.keys():
            for disease in disease_match_number.keys():
                if slot in self.disease_symptom[disease]["Symptom"] and inform_slots[slot] == True:
                    disease_match_number[disease]["yes"] += 1
                elif slot in self.disease_symptom[disease]["Symptom"] and inform_slots[slot] == dialogue_configuration.I_DO_NOT_KNOW:
                    disease_match_number[disease]["not_sure"] += 1
                elif slot in self.disease_symptom[disease]["Symptom"] and inform_slots[slot] == dialogue_configuration.I_DENY:
                    disease_match_number[disease]["deny"] += 1

        # Get the ratio of informed symptom number to the number of symptoms of each disease.
        disease_score = {}
        for disease in disease_match_number.keys():
            yes_score = float(disease_match_number[disease]["yes"]) / len(self.disease_symptom[disease]["Symptom"])
            not_sure_score = float(disease_match_number[disease]["not_sure"]) / len(self.disease_symptom[disease]["Symptom"])
            deny_score = float(disease_match_number[disease]["deny"]) / len(self.disease_symptom[disease]["Symptom"])
            disease_score[disease] = yes_score - 0.5*not_sure_score - deny_score

        # Get the most probable disease that has not been wrongly informed
        sorted_diseases = sorted(disease_score.items(), key=lambda d: d[1], reverse=True)
        match_disease = sorted_diseases[1][0]
        # match_disease = max(disease_score.items(), key=lambda x: x[0220173244_AgentWithGoal_T22_lr0.0001_RFS44_RFF-22_RFNCY-1_RFIRS-1_mls0_gamma0.95_gammaW0.95_epsilon0.1_awd0_crs0_hwg0_wc0_var0_sdai0_wfrs0.0_dtft1_dataReal_World_RID3_DQN])[0] # Get the most probable disease that the user have.
        # Candidate symptom list of symptoms that belong to the most probable disease but have't been informed yet.
        candidate_symptoms = []
        for symptom in self.disease_symptom[match_disease]["Symptom"]:
            if symptom not in inform_slots.keys():
                candidate_symptoms.append(symptom)
        return {"disease":match_disease,"candidate_symptoms":candidate_symptoms}

    def train_mode(self):
        pass

    def eval_mode(self):
        pass