
from json_ import *

class MobError(Exception):
    pass

class Objmc:
    def __init__(self, model:str, nfames:int, tickstep:int):
        self.model = model
        self.nfames = nfames
        self.tickstep = tickstep
        self.nticks = nfames*tickstep

class Entity:

    id = 0

    def __init__(self, mob:str, name:JTxt=None, hp:int|float=None, baby:bool=False, silent:bool=False, invisible:bool=False, follow_range:int|float=None, movement_speed:int|float=None, attack_damage:int|float=None, knockback_resistance:int|float=None, right_hand:str=None, left_hand:str=None, feet:str=None, legs:str=None, chest:str=None, head:str=None, tags:list[str]=[], commands:list[str]=[], other=None, death_trigger:bool=False, Mtype:str=None, custom_attack:bool=False, custom_sound:bool=False, objmc:Objmc=None, overwrite_summon:str=None):
        self.mob = mob
        self.name = name
        self.name_ = name.plain_() if name != None else '#'+str(Enemy.id)
        self.baby = baby
        self.silent = silent
        self.invisible = invisible

        self.hp = hp
        self.follow_range = follow_range
        self.movement_speed = movement_speed
        self.attack_damage = attack_damage
        self.knockback_resistance = knockback_resistance

        self.right_hand = 'Unbreakable:1b,' + right_hand if right_hand != None else ''
        self.left_hand = 'Unbreakable:1b,' + left_hand if left_hand != None else ''

        self.feet = '' if feet == None else 'Unbreakable:1b,' + feet if 'boots' in feet else feet
        self.legs = '' if legs == None else 'Unbreakable:1b,' + legs if 'boots' in legs else legs
        self.chest = '' if chest == None else 'Unbreakable:1b,' + chest if 'boots' in chest else chest
        self.head = '' if head == None else 'Unbreakable:1b,' + head if 'boots' in head else head

        self.icon = {"item":"slime_ball", "nbt":"CustomModelData:5000"}
        if isinstance(head, str):

            self.icon["item"] = [s for s in head.split(',') if "id" in s][0][4:-1]
            self.icon["nbt"] = head[head.index("tag:{")+len("tag:{"):-1].replace('"','\\"')

        for i in ['feet', 'legs', 'chest', 'head']:
            attr = getattr(self, i)
            if attr!= '' and 'tag:{SkullOwner' not in attr:
                if 'tag:{' in attr:
                    setattr(self, i, attr.replace('tag:{', 'tag:{AttributeModifiers:[{AttributeName:"generic.armor",Name:"generic.armor",Amount:0,Operation:0,UUID:[I;1,1,1,1]},{AttributeName:"generic.armor_toughness",Name:"generic.armor_toughness",Amount:0,Operation:0,UUID:[I;1,1,1,1]}],'))
                else:
                    setattr(self, i, attr + ',tag:{AttributeModifiers:[{AttributeName:"generic.armor",Name:"generic.armor",Amount:0,Operation:0,UUID:[I;1,1,1,1]},{AttributeName:"generic.armor_toughness",Name:"generic.armor_toughness",Amount:0,Operation:0,UUID:[I;1,1,1,1]}]}')

        for i in ['right_hand', 'left_hand']:
            attr = getattr(self, i)
            if attr!= '' and any(weapon in attr for weapon in ["sword", "shovel", "axe", "hoe", "pickaxe"]) :
                if 'tag:{' in attr:
                    setattr(self, i, attr.replace('tag:{', 'tag:{AttributeModifiers:[{AttributeName:"generic.attack_damage",Name:"generic.attack_damage",Amount:0,Operation:0,UUID:[I;1,1,1,1]}],'))
                else:
                    setattr(self, i, attr + ',tag:{AttributeModifiers:[{AttributeName:"generic.attack_damage",Name:"generic.attack_damage",Amount:0,Operation:0,UUID:[I;1,1,1,1]}]}')

        self.tags = tags
        self.commands = commands
        self.other = other
        self.death_trigger = death_trigger
        self.type = Mtype
        self.custom_attack = custom_attack
        self.custom_sound = custom_sound
        self.objmc = objmc
        self.overwrite_summon = overwrite_summon

        Entity.id += 1

    def nbt(self, cursed = False):
        f1 = 0.3 if cursed else 0
        f2 = 0.1 if cursed else 0

        name = "CustomName:'{0}',CustomNameVisible:1,".format(self.name.json()) if self.name != None else ''
        baby = 'IsBaby:{0},'.format(self.baby) if self.baby == True else ''
        silent = 'Silent:1b,' if self.silent == True else ''
        hp = 'Health:{0:0.2f},'.format(self.hp+abs(self.hp*f1)) if self.hp != None else ''
        other = self.other+"," if self.other != None else ''

        hp_atr = '{{Name:"generic.max_health",Base:{0:0.2f}}},'.format(self.hp+abs(self.hp*f1)) if self.hp != None else ''
        range = '{{Name:"generic.follow_range",Base:{0:0.2f}}},'.format(self.follow_range+abs(self.follow_range*f2)) if self.follow_range != None else ''
        damage = '{{Name:"generic.attack_damage",Base:{0:0.2f}}},'.format(self.attack_damage+abs(self.attack_damage*f1)) if self.attack_damage != None else ''
        speed = '{{Name:"generic.movement_speed",Base:{0:0.2f}}},'.format(self.movement_speed) if self.movement_speed != None else ''
        k_Res = '{{Name:"generic.knockback_resistance",Base:{0:0.2f}}},'.format(self.knockback_resistance+abs(self.knockback_resistance*f2)) if self.knockback_resistance != None else ''
        attr = hp_atr + range + damage + speed + k_Res
        if attr != '':
            attr = 'Attributes:[{0}],'.format(attr[:-1])

        if self.right_hand != None or self.left_hand != None:
            hands = 'HandItems:[{{{0}}},{{{1}}}],'.format(self.right_hand, self.left_hand)

        if self.feet != None or self.legs != None or self.chest != None or self.head != None:
            armor = 'ArmorItems:[{{{0}}},{{{1}}},{{{2}}},{{{3}}}],'.format(self.feet, self.legs, self.chest, self.head)

        tags = [self.type, self.name_, "EB", "init"] + self.tags
        if cursed:
            tags.append("cursed")
        if self.death_trigger:
            tags.append("death_trigger")
        if self.custom_attack:
            tags.append("custom_attack")
        if self.custom_sound:
            tags.append("custom_sound")
        if self.objmc != None:
            tags.append("objmc_model")

        invisible = ''
        if self.invisible:
            invisible = "ActiveEffects:[{{Id:14,Amplifier:1b,Duration:720000,ShowParticles:0b}}],Passengers:[{{id:'area_effect_cloud',CustomNameVisible:1b,Duration:2147483647,Tags:['unspellable','must_ride','iname','EB'],CustomName:'{}'}}],".format(self.name.json())

        return '{{{0}{1}{2}{3}{4}{5}{6}{7}{8}Tags:{9},DeathLootTable:"mdd:drop_marker",HandDropChances:[0.0F,0.0F],ArmorDropChances:[0.0F,0.0F,0.0F,0.0F]}}'.format(name, baby, hp, attr, hands, armor, silent, other, invisible, tags)



class Enemy(Entity):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.type="enemy"

class Boss(Entity):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.type="boss"

class Slime(Entity):

    def __init__(self, *args, **kwargs):
        if 'size' in kwargs:
            size = kwargs.pop('size')
            if size not in range(256) and size != None:
                raise MobError('Size must be bettwen 0-255')
            self.size = "normal" if size == None else size

        new_kwargs = dict(kwargs, mob="slime")
        super().__init__(*args, **new_kwargs)
        self.type = kwargs['Mtype'] if 'Mtype' in kwargs else "enemy"

    def nbt(self, *args, **kwargs):
        if self.size != None:
            return super().nbt(*args, **kwargs).replace("Tags:","Size:{0},Tags:".format(self.size))
        return super().nbt(*args, **kwargs)

class Panda(Entity):

    def __init__(self, *args, **kwargs):
        if kwargs['gene'] != None:
            gene = kwargs.pop('gene')
            self.gene = "normal" if gene == None else gene
        new_kwargs = dict(kwargs, mob="panda")
        super().__init__(*args, **new_kwargs)
        self.type="enemy"

    def nbt(self, *args, **kwargs):
        return super().nbt(*args, **kwargs).replace("Tags:","MainGene:{0},Tags:".format(self.gene))

class Creeper(Entity):

    def __init__(self, *args, **kwargs):
        if kwargs['powered'] != None:
            self.powered = kwargs.pop('powered')
        if kwargs['explosion_radius'] != None:
            self.explosion_radius = kwargs.pop('explosion_radius')
        new_kwargs = dict(kwargs, mob="creeper")
        super().__init__(*args, **new_kwargs)
        self.type="enemy"

    def nbt(self, *args, **kwargs):
        nbt = super().nbt(*args, **kwargs)
        if self.explosion_radius != None:
            nbt = nbt.replace("Tags:","ExplosionRadius:{0},Tags:".format(self.explosion_radius))
        if self.powered != None:
            nbt = nbt.replace("Tags:","powered:{0},Tags:".format(self.powered))
        return nbt