import os
import json
import random
import shutil
import shortuuid

from mctextworld.utils import *

class ActionLibrary:
    '''
    ActionLibrary: This is a action library for test the online planner in Minecraft.
    "mine_log": {
        "output": {"log": 1},
        "type": "mine",
        "precondition": {},
        "tool": {}
    }
    '''
    def __init__(self, action_lib):
        basepath = os.path.abspath(__file__)
        folder = os.path.dirname(basepath)
        action_lib_name = "action_lib.json"
        action_lib_patch_name = action_lib

        action_lib_path = os.path.join(folder, "action_libs", action_lib_name)
        action_lib_patch_path = os.path.join(folder, "action_libs", f'{action_lib_patch_name}.json')
        
        self.action_lib_path = action_lib_path
        self.action_lib_patch_path = action_lib_patch_path
        self.action_lib = self.load_action_lib()
        self.all_actions = list(self.action_lib.keys())

        print(f"Action Library: {len(self.all_actions)}") # 732
        print(f"Action Library: {len(set(self.all_actions))}") # 732

        self._init_oracle_item_to_action_dict()

    def load_action_lib(self):
        with open(self.action_lib_path, 'r') as f:
            action_lib = json.load(f)

        if "default" in self.action_lib_patch_path:
            print(f"Action Library Name: {os.path.basename(self.action_lib_path)}")
            return dict(action_lib)

        with open(self.action_lib_patch_path, 'r') as f:
            action_lib_patch = json.load(f)

        for key in action_lib_patch["delete"]:
            del action_lib[key]

        for key, value in action_lib_patch["replace"].items():
            action_lib[key] = value

        for key, value in action_lib_patch["add"].items():
            action_lib[key] = value

        print(f"Action Library Name: {os.path.basename(self.action_lib_patch_path)}")
        return dict(action_lib)

    def check_action(self, inventory:dict, action:str):
        if action not in self.all_actions:
            return None, 'invalid action!'
            # raise Exception('action NOT in action space!')
        else:
            for act in self.action_lib[action]:
                if check_dict(inventory, act['precondition']) and check_dict(inventory, act['tool']):
                    return act, 'valid action.'
            return None, 'invalid action!'

    def get_candidate_actions(self, inventory:dict):
        candidate_actions = []
        for action in self.all_actions:
            for cand_action in self.action_lib[action]:
                if check_dict(inventory, cand_action['precondition']) and check_dict(inventory, cand_action['tool']):
                    candidate_actions.append(action)
        return candidate_actions
    
    def _init_oracle_item_to_action_dict(self):
        self.oracle_item_to_action_dict = {}

        for a in self.all_actions:
            if a == 'no_op':
                continue

            if 'craft_' in a:
                item = a.replace('craft_', '')
            elif 'smelt_' in a:
                item = a.replace('smelt_', '')
            elif 'mine_' in a:
                item = a.replace('mine_', '')

            self.oracle_item_to_action_dict[item] = a

    def get_oracle_action_for_waypoint(self, item:str):
        if "log" in item:
            return "mine_oak_log"
        if "planks" in item:
            return "craft_oak_planks"
        
        if item == "coals" or item == "coal":
            return "mine_coal"

        if item in self.oracle_item_to_action_dict:
            return self.oracle_item_to_action_dict[item]
        else:
            return 'action_would_fail'
