from functools import partial

from siege import game
from siege.component import Component, ComponentDefinition
from siege.util import seconds, Timer
from siege.world import World
from siege.world.realm import Layer


SPAWNER_DETECTION_RANGE = 500


def positionAtSpawner(spawner, entity):
    position = spawner.getPosition()
    position.y += (entity.physics.getWorldBody().height - entity.render.getRect().height) / 2
    entity.setPosition(position + entity.monster.spawnOffset)


class MonsterNameRatio(object):
    def __init__(self, monsterPath, weight=1):
        self.monsterPath = monsterPath
        self.weight = weight


class Spawner(ComponentDefinition):
    def __init__(self):
        ComponentDefinition.__init__(self)
        self.spawnDelay = seconds(4)  # how long "spawning" animation should play before spawning
        self.frequency = seconds(30)
        self.monsters = []
        self.biomes = []
        self.loot = []
        self.freeze()

    def getType(self):
        return SpawnerComponent.TYPE


class SpawnerComponent(Component):
    TYPE = "spawner"
    CID = 0
    VERSION = 1

    def getType(self):
        return SpawnerComponent.TYPE

    def __init__(self, definition):
        Component.__init__(self)
        self.spawnDelay = definition.spawnDelay
        self.biomes = definition.biomes
        self.monsters = definition.monsters
        self.frequency = definition.frequency
        self.loot = definition.loot
        self.spawnTimer = Timer()
        self.freeze()

    def update(self, frameTime):
        self.spawnTimer.update(frameTime)

    def spawnMonster(self, level, callback):
        self.entity.animation.play("spawning")
        game.timer.add(self.spawnDelay, partial(self.finishSpawning, level, callback), isPrecise=True)
        self.spawnTimer.reset(self.frequency)

    def finishSpawning(self, level, callback):
        self.entity.animation.play("floor")
        content = game.content.get(self.monsters[0].monsterPath)
        spawner = self.getParent()
        entity = game.entity.create(content)
        entity.monster.setSpawner(spawner)
        entity.monster.create()
        positionAtSpawner(spawner, entity)
        entity.combat.setLevel(level)
        if level > spawner.combat.level.get() and spawner.stats.HP.isFull():
            spawner.combat.setLevel(level)
        World.get().move(entity, spawner.realm, Layer.Active)
        callback(entity)

    def canSpawnMonster(self):
        return self.spawnTimer.expired()

    @property
    def entity(self):
        return self.getParent()

    @staticmethod
    def register():
        SpawnerComponent.CID = game.entity.requestCid(SpawnerComponent.TYPE, Spawner)
