from collections import defaultdict
from . import baseline
import json

slots_informable = ["area","food","pricerange","name", "hastv", "hasinternet", "childrenallowed", "near", "hasmusic", "type"]


def S(turn, ontology=None) :
    if ontology == None :
        _slots_informable = slots_informable[:]
    else :
        _slots_informable = list(ontology["informable"].keys())
        
    mact = []
    if "dialog-acts" in turn["output"] :
        mact = turn["output"]["dialog-acts"]
    this_slot = None
    for act in mact :
        if act["act"] in ["request"]:
            this_slot = act["slots"][0][1]
        elif act["act"] in ["expl-conf", "select"]:
            this_slot = act["slots"][0][0]
    # return a dict of informable slots to mentioned values in a turn
    out = defaultdict(set)
    for act in mact :
        if "conf" in act["act"]  :
            for slot, value in act["slots"] :
                if slot in _slots_informable :
                    out[slot].add(value)

    for slu_hyp in turn["input"]["live"]["slu-hyps"] :
        for act in slu_hyp["slu-hyp"] :
            for slot, value in act["slots"] :
                if slot == "this" :
                    slot = this_slot
                if slot in _slots_informable :
                    out[slot].add(value)

    return out


def S_requested(turn):
    # which slots are hypothesised to be requested in this turn?
    requested = []
    for slu_hyp in turn["input"]["live"]["slu-hyps"]:
        for act in slu_hyp["slu-hyp"] :
            if act["act"] != "request" :
                continue
            for slot, value in act["slots"]:
                if slot == "slot" :
                    requested.append(value)

    return requested


def SysInformed(turn):
    # which slots are informed in this turn?
    informed = set([])
    macts = []
    if "dialog-acts" in turn["output"] :
        macts = turn["output"]["dialog-acts"]
    for mact in macts:
        if mact['act'] == 'inform' or mact['act']== 'offer' :
            for slot, _value in mact['slots']:
                informed.add(slot)
    return informed

def MethodLabel(user_act, mact) :
    method="none"
    act_types = [act["act"] for act in user_act]
    mact_types = [act["act"] for act in mact]
    if "reqalts" in act_types :
        method = "byalternatives"
    elif "bye" in act_types :
        method = "finished"
    elif "inform" in act_types:
        method = "byconstraints"
        for act in [uact for uact in user_act if uact["act"] == "inform"] :
            slots = [slot for slot, _ in act["slots"]]
            if "name" in slots :
                method = "byname"
    return method

def LabelsB(session, ontology) :
    # calculate labelling scheme B labels: (for goal and method)
    goal_labels_b = []
    method_labels_b = []
    slots_informable = list(ontology["informable"].keys())
    canthelped = {slot:[] for slot in slots_informable}
    for (log_turn,label_turn) in session :
        user_act = label_turn["semantics"]["json"]
        mact = log_turn["output"]["dialog-acts"]
        _, _, _, new_method = baseline.labels(user_act, mact)
        method_label = new_method
        method_labels_b.append(method_label)
        
        if method_label != None :
            for i in range(len(method_labels_b)-1) :
                if method_labels_b[i] == None :
                    method_labels_b[i] = method_label
        
        this_label = {}
        
        for dact in log_turn["output"]["dialog-acts"] :
            if dact["act"] == "canthelp" :
                for slot, value in dact["slots"] :
                    canthelped[slot].append(value)
                    
        for slot in slots_informable :
            
                        
            if slot in label_turn["goal-labels"] and label_turn["goal-labels"][slot] not in canthelped[slot] :
                this_label[slot] = label_turn["goal-labels"][slot]
                for _label in goal_labels_b :
                    if _label[slot] == None :
                        _label[slot] = label_turn["goal-labels"][slot]
            else :
                this_label[slot] = None
                        
        goal_labels_b.append(this_label)
        
    for i in range(len(goal_labels_b)):
        to_delete = []
        for slot in goal_labels_b[i] :
            if goal_labels_b[i][slot] == None:
                to_delete.append(slot)
        for slot in to_delete :
            del goal_labels_b[i][slot]
            
    return goal_labels_b, method_labels_b


if __name__ == '__main__':
    pass