from core.combat import applyDamage

from siege import game
from siege.component import Component, ComponentDefinition, ComponentFactory, Direction


class Descent(ComponentDefinition):
    def __init__(self, threshold=256, factor=1.0):
        ComponentDefinition.__init__(self)
        self.threshold = threshold
        self.factor = factor
        self.freeze()

    def getType(self):
        return DescentComponent.TYPE


class DescentComponent(Component):
    '''Component Dependencies: Physics, Stats, Combat'''

    TYPE = "descent"
    CID = 0
    VERSION = 1

    @staticmethod
    def create(entity, componentType, definition):
        if entity.isContentEntity():
            entity.add(DescentComponent(definition, None))
            component = None  # Set component to None here so that the BasicSystem does not manage the component
        else:
            component = DescentComponent(definition, entity.physics)
            entity.add(component)
        return component

    def __init__(self, definition, physics):
        Component.__init__(self)
        self.threshold = definition.threshold
        self.factor = definition.factor
        if physics:
            physics.onTimeStep.listen(self.handleTimeStep)
        self.descentStart = 0
        self.freeze()

    def handleTimeStep(self, physics, timestep):
        isTouchingGround = physics.isTouching(Direction.BOTTOM)
        position = physics.getCenter()
        if isTouchingGround:
            entity = self.getParent()
            if not entity.combat.isInvincible.get() and self.shouldTakeDamage(position):
                hp = entity.stats.HP
                percentage = (10 + (position.y - self.descentStart - self.threshold) / 5) * self.factor / 100.0
                damage = int(hp.getMax() * percentage)
                applyDamage(entity, damage, origin=None, knockback=None, deathMessage="DeathDescent")
        if isTouchingGround or physics.getVelocity().y < 0:
            self.descentStart = position.y

    def shouldTakeDamage(self, position):
        return self.descentStart != 0 and (position.y - self.descentStart) > self.threshold

    def reset(self):
        self.descentStart = self.getParent().physics.getCenter().y

    @staticmethod
    def register():
        DescentComponent.CID = game.entity.requestCid(DescentComponent.TYPE, Descent)
        game.registerComponent(DescentComponent.TYPE, ComponentFactory.create(DescentComponent.create))
