from functools import partial

from core.helper import select, sendMessage
from core.item.armor import addPotentials
from core.talent import createSkill
from core.tuning.skill import SkillTuning

from siege import Locale, game, Talent
from siege.util import Random


def getTalent():
    talent = Talent("craft", "craft/icon.png", [1000] * 20)
    talent.skills.append(Expertise.create())
    talent.skills.append(Efficiency.create())
    talent.skills.append(Artisan.create())
    talent.skills.append(Concentrate.create())
    talent.skills.append(Armorer.create())
    talent.skills.append(Smith.create())
    talent.skills.append(Fundamentals.create())
    talent.skills.append(Duplicate.create())
    talent.skills.append(Refine.create())
    game.events['create_talent'].invoke(talent)
    return talent


class Expertise(object):
    @staticmethod
    def onActivate(level, player):
        player.entity.event["craft_quality"].listen(partial(Expertise.handleCraftQuality, level))

    @staticmethod
    def onDeactivate(level, player):
        player.entity.event["craft_quality"].remove(partial(Expertise.handleCraftQuality, level))

    @staticmethod
    def handleCraftQuality(level, player, results, craft, quality, maxQuality):
        results.maxQuality += level * SkillTuning.EXPERTISE.AMOUNT_PER_LEVEL

    @staticmethod
    def description(level):
        return Locale.getEscaped("ExpertiseDesc")

    @staticmethod
    def create():
        return createSkill(Expertise, SkillTuning.EXPERTISE)


class Efficiency(object):
    @staticmethod
    def onActivate(level, player):
        player.entity.event["craft_start"].listen(partial(Efficiency.handleCraftStart, level))

    @staticmethod
    def onDeactivate(level, player):
        player.entity.event["craft_start"].remove(partial(Efficiency.handleCraftStart, level))

    @staticmethod
    def handleCraftStart(level, player, results, craft, count, materials):
        if SkillTuning.EFFICIENCY.AMOUNT_PER_LEVEL * level < Random.get(100):
            return
        #Randomly select a material until one is found that has multiple quantities
        tempMaterials = [material for material in materials]
        while tempMaterials:
            material = select(tempMaterials)
            if material.quantity > 1:
                material.quantity -= 1
                sendMessage("general", "System", "EfficiencyMsg", player.networkId, item=material.entity.name)
                break

    @staticmethod
    def description(level):
        return Locale.getEscaped("EfficiencyDesc")

    @staticmethod
    def create():
        return createSkill(Efficiency, SkillTuning.EFFICIENCY)


class Artisan(object):
    ICON = SkillTuning.ARTISAN.ICON

    def __init__(self, owner, level, duration):
        self.level = level
        owner.event["craft_quality"].listen(self.handleCraftQuality)

    def onRemove(self, owner):
        owner.event["craft_quality"].remove(self.handleCraftQuality)

    def isPositive(self):
        return True

    def handleCraftQuality(self, player, results, craft, quality, maxQuality):
        results.quality += self.level * self.AMOUNT_PER_LEVEL
        player.entity.effects.remove(SkillTuning.ARTISAN.name)

    @staticmethod
    def onUse(player, level, position, index, slot, tool):
        player.entity.effects.add(SkillTuning.ARTISAN.NAME, level, SkillTuning.ARTISAN.DURATION)
        #TODO: Play an animation on the player and sfx

    @staticmethod
    def description(level):
        return Locale.getEscaped("ArtisanDesc")

    @staticmethod
    def create():
        game.effects.register(SkillTuning.ARTISAN.NAME, Artisan)
        return createSkill(Artisan, SkillTuning.ARTISAN)


class Concentrate(object):
    ICON = SkillTuning.CONCENTRATE.ICON

    def __init__(self, player, level, duration):
        player.event["craft_random"].listen(self.handleCraftRandom)
        player.event["craft_finish"].listen(self.handleCraftFinish)

    def onRemove(self, player):
        player.event["craft_random"].remove(self.handleCraftRandom)
        player.event["craft_finish"].remove(self.handleCraftFinish)

    def handleCraftRandom(self, player, results, craft, quality, result, chance, random):
        results.random = 0
        player.entity.effects.remove(SkillTuning.CONCENTRATE.NAME)

    def isPositive(self):
        return True

    def handleCraftFinish(self, player, results, craft, count, result, item, remainder):
        effects = player.entity.effects
        if effects.has(SkillTuning.CONCENTRATE.NAME):
            effects.remove(SkillTuning.CONCENTRATE.NAME)
        else:
            self.onRemove(player.entity)

    @staticmethod
    def onUse(player, level, position, index, slot, tool):
        player.entity.effects.add(SkillTuning.CONCENTRATE.NAME, level, SkillTuning.CONCENTRATE.DURATION)
        #TODO: Play an animation on the player and sfx

    @staticmethod
    def description(level):
        return Locale.getEscaped("ConcentrateDesc")

    @staticmethod
    def create():
        game.effects.register(SkillTuning.CONCENTRATE.NAME, Concentrate)
        return createSkill(Concentrate, SkillTuning.CONCENTRATE)


class Armorer(object):
    @staticmethod
    def onActivate(level, player):
        player.entity.event["craft_quality"].listen(partial(Armorer.handleCraftQuality, level))

    @staticmethod
    def onDeactivate(level, player):
        player.entity.event["craft_quality"].remove(partial(Armorer.handleCraftQuality, level))

    @staticmethod
    def handleCraftQuality(level, player, results, craft, quality, maxQuality):
        if craft.category == "Armor":
            results.quality += level * SkillTuning.ARMORER.AMOUNT_PER_LEVEL

    @staticmethod
    def description(level):
        return Locale.getEscaped("ArmorerDesc")

    @staticmethod
    def create():
        return createSkill(Armorer, SkillTuning.ARMORER)


class Smith(object):
    @staticmethod
    def onActivate(level, player):
        player.entity.event["craft_quality"].listen(partial(Smith.handleCraftQuality, level))

    @staticmethod
    def onDeactivate(level, player):
        player.entity.event["craft_quality"].remove(partial(Smith.handleCraftQuality, level))

    @staticmethod
    def handleCraftQuality(level, player, results, craft, quality, maxQuality):
        if craft.category == SkillTuning.SMITH.CATEGORY:
            results.quality += level * SkillTuning.SMITH.AMOUNT_PER_LEVEL

    @staticmethod
    def description(level):
        return Locale.getEscaped("SmithDesc")

    @staticmethod
    def create():
        return createSkill(Smith, SkillTuning.SMITH)


class Fundamentals(object):
    @staticmethod
    def onActivate(level, player):
        player.entity.event["craft_chance"].listen(partial(Fundamentals.handleCraftChance, level))

    @staticmethod
    def onDeactivate(level, player):
        player.entity.event["craft_chance"].remove(partial(Fundamentals.handleCraftChance, level))

    @staticmethod
    def handleCraftChance(level, player, results, craft, quality, result, chance):
        minLevel = player.entity.talents.craft.level.get() - (SkillTuning.FUNDAMENTALS.START_LEVEL - level)
        if minLevel >= craft.level:
            results.chance += level * SkillTuning.FUNDAMENTALS.AMOUNT_PER_LEVEL

    @staticmethod
    def description(level):
        return Locale.getEscaped("FundamentalsDesc")

    @staticmethod
    def create():
        return createSkill(Fundamentals, SkillTuning.FUNDAMENTALS)


class Duplicate(object):
    @staticmethod
    def onActivate(level, player):
        player.entity.event["craft_finish"].listen(partial(Duplicate.handleCraftFinish, level))

    @staticmethod
    def onDeactivate(level, player):
        player.entity.event["craft_finish"].remove(partial(Duplicate.handleCraftFinish, level))

    @staticmethod
    def handleCraftFinish(level, player, results, craft, count, result, item, remainder):
        if not item.entity.item.isUnique and SkillTuning.DUPLICATE.AMOUNT_PER_LEVEL * level >= Random.get(100):
            player.entity.inventory.add(item.entity, 1)

    @staticmethod
    def description(level):
        return Locale.getEscaped("DuplicateDesc")

    @staticmethod
    def create():
        return createSkill(Duplicate, SkillTuning.DUPLICATE)


class Refine(object):
    def __init__(self, owner, level, duration):
        owner.event["craft_finish"].listen(self.handleCraftFinish)

    def onRemove(self, owner):
        owner.event["craft_finish"].remove(self.handleCraftFinish)

    def handleCraftFinish(self, player, results, craft, count, result, item, remainder):
        if item.entity.has('equipment'):
            component = item.entity.equipment
            if not component.isFull() and component.potentials:
                addPotentials(component, 1)
            player.entity.effects.remove(SkillTuning.REFINE.NAME)

    def isPositive(self):
        return True

    @staticmethod
    def onUse(player, level, position, index, slot, tool):
        player.entity.effects.add(SkillTuning.REFINE.NAME, level, SkillTuning.REFINE.DURATION)
        #TODO: Play an animation on the player and sfx

    @staticmethod
    def description(level):
        return Locale.getEscaped("RefineDesc")

    @staticmethod
    def create():
        game.effects.register(SkillTuning.REFINE.NAME, Refine)
        return createSkill(Refine, SkillTuning.REFINE)
