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

from json import *
from inspect import getmembers

class NbtError(Exception):
    pass
class LoreError(NbtError):
    pass
class StatError(NbtError):
    pass
class StatsError(NbtError):
    pass

class Lore:

    def __init__(self, l = None):
        if isinstance(l, list):
            for i,line in enumerate(l):
                if not isinstance(line, (JPar, JLine)):
                    raise LoreError("Must be a JPar or JLine in [{0}]".format(i))
        self.lore = l

    def newpar(self, l):
        if isinstance(l, JPar):
            self.lore.append(l)
        elif isinstance(l, (JTxt, JLine, str)):
            self.lore.append(JPar([l]))
        else:
            print('Must be a Json type or str')

    def newline(self, l):
        if isinstance(l, JLine):
            self.lore.append(l)
        elif isinstance(l, (JTxt, str)):
            self.lore.append(JLine([l]))
        else:
            print('Must be a JTxt, JLine type or str')

    def blankline(self):
        self.lore.append(JLine(''))

    def json(self, format = 'item'):
        txt = []
        if format == 'advancement':
            txt = ['\n\t\t\t\t\t\t{"text":"","bold":false,"italic":false,"underlined":false,"obfuscated":false}']

        for json_t in self.lore:
            if format == 'advancement':
                txt.append("\n\t\t\t\t\t\t{0}".format(json_t.json('advancement')))
            else:
                txt.append(json_t.json())

        if format == 'advancement':
            return "["+','.join(txt)+"\n\t\t\t\t]"
        return "["+','.join(txt)+"]"

    def __getitem__(self, i):
        return self.lore[i]

class Stat:

    uuid = 1

    sl = ['any','hand','mainhand','offhand','armor']
    mc = ['attack_damage', 'max_health', 'movement_speed', 'knockback_resistance', 'armor', 'armor_toughness', 'attack_speed']
    translation = ['dmg', 'hp', 'speed', 'knock_resist', 'armor', 'armor_th', 'attk_speed']
    custom = ['curse', 'luck', 'mana_speed', 'mana_cost', 'mana_capacity', 'souls_capacity']
    tl = mc + custom

    def __init__(self, type, value, slot = 'any'):
        self.type = type        # one of items of tl list
        self.value = value      # int, float
        self.slot = slot        # one of items of tl sl
        self.uuid = Stat.uuid
        Stat.uuid += 1

        if type in Stat.translation:
            self.type = Stat.mc[Stat.translation.index(type)]

    def attibute(self, armor_piece = None):
        if self.type in Stat.mc and self.slot != 'any':
            slot = self.slot if self.slot != 'armor' else armor_piece
            if self.slot == 'hand':
                return '{{AttributeName:"generic.{0}",Name:"generic.{0}",Amount:{1},Operation:0,UUID:[I;{2},{2},{2},{2}],Slot:"mainhand"}},{{AttributeName:"generic.{0}",Name:"generic.{0}",Amount:{1},Operation:0,UUID:[I;{2},{2},{2},{2}],Slot:"offhand"}}'.format(self.type, self.value, self.uuid)
            else:
                return '{{AttributeName:"generic.{0}",Name:"generic.{0}",Amount:{1},Operation:0,UUID:[I;{2},{2},{2},{2}],Slot:"{3}"}}'.format(self.type, self.value, self.uuid, slot)
        return ''

class Stats:
    mc = ['attack_damage', 'max_health', 'movement_speed', 'knockback_resistance', 'armor', 'armor_toughness', 'attack_speed']
    custom = ['curse', 'luck', 'mana_speed', 'mana_cost', 'mana_capacity', 'souls_capacity']

    def __init__(self, stats = []):

        self.stats = {}
        self.add(stats)

    def add(self, l = []):
        # Check is list or Stat
        if isinstance(l, Stat):
            l = [l]
        elif isinstance(l, list):
            for i,stat in enumerate(l):
                if not isinstance(stat, Stat):
                    raise StatsError('stat[{}] must be a Stat obj'.format(i))
        else:
            raise Statserror('l must be stat a list of Stats')

        for stat in l:
            # Type not registred
            if stat.type not in self.stats:
                self.stats[stat.type] = [stat]
            # Type registred
            else:
                # Slot conflict check
                for s in self.stats[stat.type]:
                    if stat.slot == s.slot:
                        raise StatsError("{}: {} {} conflicted with {}: {} {}. Can't have two of the same slot.".format( stat.type, stat.value, stat.slot, s.type, s.value, s.slot ) )
                # Conflict passed
                self.stats[stat.type].append(stat)

    def nbt(self):
        txt = []
        for type in self.stats:
            tmp = []
            for stat in self.stats[type]:
                if stat.slot == 'hand':
                    tmp.append('{{value:{},slot:{}}}'.format(stat.value, 'mainhand'))
                    tmp.append('{{value:{},slot:{}}}'.format(stat.value, 'offhand'))
                else:
                    tmp.append('{{value:{},slot:{}}}'.format(stat.value, stat.slot))
            txt.append("{}:[{}]".format(type, ','.join(tmp)))


        return 'stats:{{{}}}'.format(','.join(txt))

    def lore(self):
        txt = []
        dic = {
                "max_health":"\\\\uf810",
                "attack_damage":"\\\\uf811",
                "attack_speed":"\\\\uf812",
                "movement_speed":"\\\\uf813",
                "armor":"\\\\uf814",
                "armor_toughness":"\\\\uf815",
                "knockback_resistance":"\\\\uf816",
                "mana_capacity":"\\\\uf817",
                "mana_speed":"\\\\uf818",
                "mana_cost":"\\\\uf819",
                "souls_capacity":"\\\\uf81a",
                "luck":"\\\\uf81b",
                "curse":"\\\\uf81c"
            }

        for i, type in enumerate(self.stats):
            for j, stat in enumerate(self.stats[type]):
                l = [ JTxt("\\n  \\\\u2022 {:+}".format(stat.value), italic=True ) ]
                if type in ['luck', 'mana_cost']:
                    l.append( JTxt('%', italic = True ))
                l.append( JTxt(" "+dic[stat.type], 'white', italic=True ) )
                if stat.slot != 'any':
                    l.append( JTxt(" (", italic=True ) )
                    if stat.slot == 'armor':
                        l.append( JTxt('equipped', italic=True ) )
                    else:
                        l.append( JTxt(stat.slot, italic=True ) )
                    l.append( JTxt(")", italic=True ) )
                txt.append(JLine(l))

        if len(txt) > 0:
            txt.insert(0, JLine(['\\n', JTxt('stats', 'gray'), ': '], 'gray'))
        return txt

    def attributes(self, armor_piece = None):
        txt = []
        for type in self.stats:
            for stat in self.stats[type]:
                tmp = stat.attibute(armor_piece)
                if tmp != '':
                    txt.append(tmp)
        if len(txt) > 0:
            return ',AttributeModifiers:['+','.join(txt)+']'
        return ''

    def get_anySlot_McStats(self):
        stats = []
        for type in self.stats:
            for stat in self.stats[type]:
                if stat.slot == "any" and stat.type in Stats.mc:
                    stats.append(stat)
        return stats

    def get_anySlot_CustomStats(self):
        stats = []
        for type in self.stats:
            for stat in self.stats[type]:
                if stat.slot == "any" and stat.type in Stats.custom:
                    stats.append(stat)
        return stats
