# -*- coding: utf-8 -*-

import os
from mob import *
from json_ import *

class GenError(Exception):
    pass

class Generator:

    def __init__(self, l, type = "enemies", floor = "Other"):
        self.type = type
        self.floor = floor
        self.floor_ = floor.replace(' ', '_').lower()
        self.mobs = []
        self.add(l)

    def add(self, l):
        if isinstance(l, list):
            for i,mob in enumerate(l):
                if isinstance(mob, Entity):
                    self.mobs.append(mob)
                else:
                    raise GenError('mob {0} must be a list of Entity'.format(i))
        else:
            if isinstance(l, Enemy):
                self.mobs.append(l)
            else:
                raise GenError('mob must be a list of Entity')

    def make(self):
        f = '../{}_py/functions'.format(self.type)
        p = '../{}_py/predicates/death_trigger/type'.format(self.type)
        for path in [f, p]:
            if not os.path.exists(path):
                os.makedirs(path)
                print("Directory ", path , " Created ")

        for mob in self.mobs:
            self.spawn(mob)
            self.death_trigger_type(mob)

        self.book_root()
        self.book_floor_root()
        self.book_type_root()
        self.book_register_mob()
        self.death_trigger()

# -------- Book ------
    def spawn(self, mob: Entity):
        selector = f"tag={mob.name_},tag=init,sort=nearest,limit=1"

        f = open(f'../{self.type}_py/functions/{mob.name_}.mcfunction', 'w')
        f.write((
            "# Find if it will be cursed (luck based)\n"
            'execute if score summon_cursed EB_generic matches -1 run function 0_enemy_boss:summon/is_cursed\n\n'
            "# Summon if not cursed\n"
            f'execute if score summon_cursed EB_generic matches 0 run summon {mob.mob} ~ ~ ~ {mob.nbt()}\n\n'
            "# Summon if cursed\n"
            f'execute if score summon_cursed EB_generic matches 1 run summon {mob.mob} ~ ~ ~ {mob.nbt(True)}\n\n'
            "# Mark if it's a boss spawn\n"
            f"execute if score boss_spawn EB_generic matches 1 run tag @e[{selector}] add boss_spawn\n\n"
            "# Spawn count\n"
        ))
        
        if mob.type == 'boss':
            f.write(f"execute as @e[{selector}] store result score @s EB_boss_hp_soul run attribute @s generic.max_health get\n")
            f.write("execute if score spawn_count EB_generic matches 1 run scoreboard players add #bosses_spawned EB_generic 1\n")
        else:
            f.write("execute if score spawn_count EB_generic matches 1 run scoreboard players add #enemies_spawned EB_generic 1\n")
       
        f.write((
            "\n# Reset flags\n"
            "scoreboard players set summon_cursed EB_generic -1\n"
            "scoreboard players set boss_spawn EB_generic 0\n"
            "scoreboard players set spawn_count EB_generic 1\n\n"
        ))
        
        if mob.custom_sound:
            f.write((
                "# Start counters\n"
                f"execute as @e[{selector}] run function 0_enemy_boss:sound_cooldown/spawn\n\n"
            ))

        if mob.custom_attack:
            f.write((
                "# Start custom attack\n"
                f"execute as @e[{selector}] run function {self.type}:{mob.name_}/attacks/spawn_cooldown\n\n"
            ))

        if mob.objmc != None:
            f.write((
                "# AJ model\n"
                "summon armor_stand ~ ~-1.4 ~ {Marker:1b,Invisible:1b,Tags:['init','" + mob.name_ + "','unspellable','EB','objmc'],ArmorItems:[{},{},{},{id:'leather_horse_armor',Count:1b,tag:{CustomModelData:" + mob.objmc.model + ",display:{color:0}}}]}\n"
                f"execute as @e[{selector},tag=!objmc] run function olink:ch1/new_link\n"
                f"execute as @e[{selector},tag=objmc] run function olink:ch1/join_link\n"
                f"scoreboard players set nticks EB_objmc {mob.objmc.nticks}\n"
                f"execute as @e[{selector},tag=objmc] run function 0_enemy_boss:objmc/start_frame_offset\n\n"
            ))

        f.write("# Custom commands\n")
        for command in mob.commands:
            f.write(command+'\n')

        f.write("\n\n# Clear Init tag")
        f.write(f"tag @e[tag={mob.name_},tag=init,sort=nearest,limit={1 if mob.objmc == None else 2}] remove init")

        f.close()

    def book_register_mob(self):
        for i,mob in enumerate(self.mobs):
            parent_path = 'book_py:{}/{}/{}_{}'.format(self.floor_, self.type, i-1, self.mobs[i-1].name_)
            if i == 0:
                parent_path = 'book_py:{}/{}/root'.format(self.floor_, self.type)
            fpath = 'book_py:{}/{}'.format(self.type, mob.name_)

            description = '''
        [
            {{"translate":"stats","color":"gray"}},{{"text":":\\n"}},
            {{"text":"  \\u2022 {} ","color":"dark_gray"}},{{"text":"\\uf810","color":"white","italic":false}},{{"text":"\\n"}},
            {{"text":"  \\u2022 {} ","color":"dark_gray"}},{{"text":"\\uf811","color":"white","italic":false}},{{"text":"\\n"}},
            {{"text":"  \\u2022 {} ","color":"dark_gray"}},{{"text":"\\uf813","color":"white","italic":false}},{{"text":"\\n"}},
            {{"text":"  \\u2022 {} ","color":"dark_gray"}},{{"text":"\\uf816","color":"white","italic":false}}
        ]'''.format(mob.hp, mob.attack_damage, mob.movement_speed, mob.knockback_resistance if mob.knockback_resistance != None else "0")

            data = '''
{{
    "display": {{
        "title": {0}                ,
        "description": {1},
        "icon": {{
            "item": "minecraft:{2}",
            "nbt":"{{{3}}}"
        }},
        "frame": "task",
        "show_toast": true,
        "announce_to_chat": false,
        "hidden": true
    }},
    "criteria": {{
        "{4}": {{
            "trigger": "minecraft:player_killed_entity",
            "conditions": {{
                "entity":{{
                    "nbt": "{{Tags:[\\"{4}\\"]}}"
                }}
            }}
        }}
    }},
    "rewards": {{
       "function": "{5}"
    }},
    "parent": "{6}"
}}
'''.format(JLine([mob.name]).json('advancement'), description, mob.icon["item"], mob.icon["nbt"], mob.name_, fpath, parent_path)

            f = open('../book_py/advancements/{}/{}/{}_{}.json'.format(self.floor_, self.type, i, mob.name_),'w')
            f.write(data)
            f.close()

            f = open('../book_py/functions/{}/{}.mcfunction'.format(self.type, mob.name_),'w')
            f.write("advancement grant @a only book_py:{}/{}/root {}".format(self.floor_, self.type, mob.name_))
            f.close()

    def book_type_root(self):
        criteria = ''
        for i,mob in enumerate(self.mobs):
            criteria += '\n\t\t\t"{0}":{{"trigger": "minecraft:impossible"}}'.format(mob.name_)
            if i+1 < len(self.mobs):
                criteria += ','

        color = "dark_red" if self.type != "enemies" else "red"
        icon = "skeleton_skull" if self.type == "enemies" else "wither_skeleton_skull"
        data = '''
{{
    "display": {{
        "title": {{"translate": "{}", "color": "{}"}},
        "description": {{"text": ""}},
        "icon": {{
            "item": "minecraft:{}"
        }},
        "frame": "goal",
        "show_toast": true,
        "announce_to_chat": false,
        "hidden": false
    }},
    "criteria": {{ {}
    }},
    "parent": "book_py:{}/root"
}}
'''.format(self.type, color, icon, criteria, self.floor_)
        f = open("../book_py/advancements/{0}/{1}/root.json".format(self.floor_, self.type),'w')
        f.write(data)
        f.close()

    def book_floor_root(self):
        model = {"tutorial":6100,"others":6101,"community_builders":6102,"floor_1":6103,"floor_2":6104,"floor_3":6105,"floor_4":6106,"floor_5":6107}
        if 'floor' in self.floor_:
            title = '[{{"translate": "floor", "color": "gold"}}, {{"text": " {0}", "color": "gold"}}]'.format(self.floor_.split('_')[-1])
        else:
            title = '[{{"translate": "{0}", "color": "gold"}}]'.format(self.floor_)
        data = '''
{{
    "display": {{
        "title": {0},
        "description": {{"text": ""}},
        "icon": {{
            "item": "minecraft:slime_ball",
            "nbt":"{{CustomModelData:{1}}}"
        }},
        "frame": "goal",
        "show_toast": false,
        "announce_to_chat": false,
        "hidden": false
    }},
    "criteria": {{
        "null": {{"trigger": "minecraft:tick"}}
    }},
    "parent": "book_py:root"
}}
'''.format(title, model[self.floor_])
        f = open('../book_py/advancements/{}/root.json'.format(self.floor_),'w')
        f.write(data)
        f.close()

    def book_root(self):
        p = '../book_py/advancements/{}/{}'.format(self.floor_, self.type)
        if not os.path.exists(p):
            os.makedirs(p)
            print("Directory ", p , " Created ")
        p = '../book_py/functions/{}'.format(self.type)
        if not os.path.exists(p):
            os.makedirs(p)
            print("Directory ", p , " Created ")

        data = '''
{
    "display": {
        "title": {"translate": "mobs", "color": "gold"},
        "description": {"text": ""},
        "icon": {"item": "minecraft:zombie_head"},
        "frame": "challenge",
        "show_toast": false,
        "announce_to_chat": false,
        "hidden": false,
        "background": "minecraft:textures/block/nether_wart_block.png"
    },
    "criteria": {
        "null": {"trigger": "minecraft:tick"}
    }
}
'''
        f = open('../book_py/advancements/root.json','w')
        f.write(data)
        f.close()

    def death_trigger(self):
        p = open('../{0}_py/predicates/death_trigger/is_trigger.json'.format(self.type), 'w')
        p.write(
"""
{
	"condition": "minecraft:entity_properties",
	"entity": "this",
	"predicate": {
		"nbt": "{Item:{tag:{Tags:['death_trigger']}}}"
	}
}""")
        p.close()

    def death_trigger_type(self, mob: Entity):
        p = open('../{0}_py/predicates/death_trigger/type/{1}.json'.format(self.type, mob.name_), 'w')
        p.write(
"""
{
	"condition": "minecraft:entity_properties",
	"entity": "this",
	"predicate": {
		"nbt": "{Item:{tag:{Tags:['NAME']}}}"
	}
}""".replace('NAME', mob.name_))
