from functools import partial

from core.tuning import Tuning
from siege import game, InventoryItem
from siege.graphic import Color, TextureCache
# from siege.log import Log
from siege.particle import PhysicsParticleEmitter
from siege.util import PixelRect, Random, RangeColor, RangeFloat, RangeInt, RangeVector, seconds, Sizes, Vector, WeightedRandomGenerator
from siege.world.realm import Layer


def register():
    content = lambda name: game.content.get(name).id
    handlers = {
        content('pots'): handlePot,
        content('foliage'): handleFoliage,
        content('vine_bases'): handleFoliage,
        content('vine_mids'): handleFoliage,
        content('vine_ends'): handleFoliage,
    }
    game.events["hit_tile"].listen(partial(handleTileHit, handlers))
    game.data['hit_tile_handlers'] = handlers


def unregister():
    if 'hit_tile_handlers' in game.data:
        game.events['hit_tile'].remove(partial(handleTileHit, game.data['hit_tile_handlers']))


def handleTileHit(handlers, entity, realm, tile, layer, tilePosition, brokeTile):
    tileId = tile.getParent().content.id
    layerManager = realm.layers
    ground = layerManager[Layer.Ground]
    if brokeTile and layer == Layer.Ground and tile.isSolid:
        aboveTile = tilePosition.getNeighbor(0, -1)
        potsId = game.content.get('pots').id
        if ground.getTile(aboveTile) == potsId:
            layerManager.setTile(Layer.Ground, aboveTile, 0)
            handlePot(entity, realm, tile, layer, aboveTile, True)
    if tileId in handlers:
        handlers[tileId](entity, realm, tile, layer, tilePosition, brokeTile)
    elif tile.particleColor.a != 0:
        #Determine position of emitter based off of what side is open
        position = tilePosition.getWorldPosition()
        emitter = PhysicsParticleEmitter(realm.uid, realm.size.width, position, 1, 0)
        if layer == Layer.Wall:
            position.x += Sizes.TILE / 2
            position.y += Sizes.TILE / 2
        else:
            if ground.isEmpty(tilePosition.getNeighbor(0, -1)):
                position.x += Sizes.TILE / 2
                emitter.velocityStart = RangeVector(Vector(-3, -3.0), Vector(3, -6.0))
            elif ground.isEmpty(tilePosition.getNeighbor(-1, 0)):
                position.y += Sizes.TILE / 2
                emitter.velocityStart = RangeVector(Vector(-3, -3), Vector(-1, 0))
            elif ground.isEmpty(tilePosition.getNeighbor(1, 0)):
                position.x += Sizes.TILE
                position.y += Sizes.TILE / 2
                emitter.velocityStart = RangeVector(Vector(1, 0), Vector(3, 3))
            elif ground.isEmpty(tilePosition.getNeighbor(0, 1)):
                position.x += Sizes.TILE / 2
                position.y += Sizes.TILE
                emitter.velocityStart = RangeVector(Vector(-3, 0), Vector(3, 0))
        emitter.amount = Random.get(4, 6)
        emitter.setPosition(position)
        emitter.colorStart = RangeColor(tile.particleColor, tile.particleColor)
        emitter.colorEnd = emitter.colorStart
        emitter.particleLife = RangeInt(seconds(2), seconds(3))
        emitter.scaleStart = RangeVector(Vector(2, 2), Vector(2, 2))
        emitter.gravity = Vector(0.0, 0.5)
        emitter.friction = Vector(0.2, 0.0)
        emitter.restitution = Vector(0.3, 0.4)
        game.particles.add(emitter)


def handleFoliage(entity, realm, tile, layer, tilePosition, brokeTile):
    if brokeTile:
        emitter = PhysicsParticleEmitter(realm.uid, realm.size.width, Vector(0, -10), 1, 0)
        emitter.amount = Random.get(2, 4)
        coords = [
            PixelRect(0, 0, 5, 3),
            PixelRect(5, 0, 7, 5),
            PixelRect(12, 0, 5, 5)
        ]
        emitter.setTexture(TextureCache.get("mods/core/plant/vine_leaves.png"), coords)
        emitter.setPosition(tilePosition.getWorldCenter())
        emitter.particlePosition = RangeVector(Vector(-7, 2), Vector(7, -2))
        emitter.particleLife = RangeInt(seconds(1), seconds(2))
        if tile.getParent().content.id in game.grass.vineTiles:
            emitter.velocityStart = RangeVector(Vector(-1.5, 0), Vector(1.5, -1.0))
        elif tile.getParent().content.id in game.grass.foliages:
            emitter.velocityStart = RangeVector(Vector(-1.5, -2.0), Vector(1.5, -3.0))
        emitter.rotationChange = RangeFloat(-90, 90)
        emitter.gravity = Vector(0.0, 0.15)
        emitter.friction = Vector(0.2, 0.0)
        emitter.fallCap = Vector(0.0, 1.0)
        emitter.colorStart = RangeColor(Color(255, 255, 255, 255), Color(255, 255, 255, 255))
        emitter.colorEnd = RangeColor(Color(255, 255, 255, 0), Color(255, 255, 255, 0))
        game.particles.add(emitter)


def handlePot(entity, realm, tile, layer, tilePosition, brokeTile):
    if brokeTile:
        emitter = PhysicsParticleEmitter(realm.uid, realm.size.width, Vector(0, -10), 1, 0)
        emitter.amount = Random.get(2, 4)
        coords = [
            PixelRect(0, 0, 5, 6),
            PixelRect(5, 2, 4, 4),
            PixelRect(9, 3, 7, 3),
            PixelRect(16, 1, 6, 5),
            PixelRect(22, 0, 4, 6)
        ]
        emitter.setTexture(TextureCache.get("mods/core/tile/pot_shards.png"), coords)
        emitter.setPosition(tilePosition.getWorldCenter())
        emitter.particlePosition = RangeVector(Vector(-7, 2), Vector(7, -2))
        emitter.particleLife = RangeInt(seconds(2), seconds(3))
        emitter.velocityStart = RangeVector(Vector(-2, -3.0), Vector(2, -4.0))
        emitter.rotationChange = RangeFloat(-90, 90)
        emitter.gravity = Vector(0.0, 0.4)
        emitter.friction = Vector(0.05, 0.0)
        emitter.groundFriction = Vector(0.2, 0.0)
        emitter.fallCap = Vector(0.0, 2.0)
        emitter.colorStart = RangeColor(Color(255, 255, 255, 255), Color(255, 255, 255, 255))
        emitter.colorEnd = RangeColor(Color(255, 255, 255, 0), Color(255, 255, 255, 0))
        game.particles.add(emitter)
        drops = Tuning.POT_DROPS
        wrg = WeightedRandomGenerator([rate for drop, rate in drops])
        drop = drops[wrg()][0]
        if drop is not None:
            quantity = 10 if drop == 'arrow' else 1
            item = InventoryItem(game.content.get(drop), quantity)
            realm.dropped.create(item, tilePosition.getWorldPosition(), Vector(Random.get(-3, 3), -6))
