package pw.hamzantal.vagueenchants.enchantments

import hazae41.minecraft.kutils.bukkit.listen
import hazae41.minecraft.kutils.bukkit.msg
import net.minecraft.server.v1_10_R1.BlockPosition
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.Particle
import org.bukkit.Sound
import org.bukkit.craftbukkit.v1_10_R1.entity.CraftPlayer
import org.bukkit.entity.Player
import org.bukkit.event.block.BlockBreakEvent
import pw.hamzantal.vagueenchants.*
import pw.hamzantal.vagueenchants.commands.c
import java.math.BigDecimal


class Explosive(id: Int) : CustomEnchant(id, Config.explosive, "EXPLOSIVE") {

	init {
		VagueEnchants.enchants += this
		val pl = VagueEnchants.pl
		pl.registerEnchantment(this)
		pl.listen(ignoreCancelled = true, callback = this::onBreak)
	}

	private val breaking = mutableListOf<Player>()
	private val cooldowns = hashMapOf<Player, Long>()

	private fun onBreak(e: BlockBreakEvent) {
		val p = e.player
		if (this !in p.inventory.itemInMainHand?.enchantments ?: mapOf() || p in breaking) return
		if (p in cooldowns && cooldowns[p]!! > System.currentTimeMillis()) return

		val block = e.block
		val loc = block.location
		val item = p.inventory.itemInMainHand
		val level = p.inventory.itemInMainHand.enchantments[this]!!

		loc.validRegion(p)?: return
		cooldowns[p] = System.currentTimeMillis() +
				1000 * config.cooldown.x(level).toLong()

		breaking += p
		val pim = (p as CraftPlayer).handle.playerInteractManager

		loc.sphericalBlocks(config.blocks.x(level))
			.filter { it.block.type != Material.AIR && it.canMine(e.player) }
			.filter { it.validRegion(p) != null}
			.forEach {
				val nmsData = pim.world.getType(BlockPosition(it.x, it.y, it.z))
				val xp = nmsData.block.getExpDrop(pim.world, nmsData, item.enchantments[LOOT_BONUS_BLOCKS] ?: 0)
				p.giveExp(xp)

				ToolUtils.drops(it.block, item).forEach { i -> p.inventory.addItem(i) }

				it.block.type = Material.AIR
			}
		block.world.spawnParticle(Particle.EXPLOSION_HUGE, block.location, 1)
		p.playSound(loc, Sound.ENTITY_GENERIC_EXPLODE, 5F, 5F)
		breaking -= p
	}

	override fun inspect(p: Player, level: Int) {
		val cost = config.cost.x(level + 1)
		val cd = config.cooldown.x(level)
		val blocks = config.blocks.x(level).toInt()

		p.msg("&7Description: ${config.description}")
		p.msg("&7Current level: $level")
		p.msg("&7Maximum level: $maxLevel")

		if (level < maxLevel) p.msg("&7Next level cost: $cost")
		else p.msg("&7Level maxed")

		p.msg("&7Cooldown between explosions: $cd")
		if (p in cooldowns && cooldowns[p]!! > System.currentTimeMillis())
			p.msg("&7Cooldown remaining: ${(cooldowns[p]!! - System.currentTimeMillis()) / 1000} seconds")

		p.msg("&7Explosion radius: $blocks")
	}

	override fun loreString(level: Int): String {
		return "&7Explosive ${loreLevel(level)}".c
	}

	private fun Location.sphericalBlocks(r: BigDecimal): MutableList<Location> {
		val radius = r.toInt()
		val locs = mutableListOf<Location>()
		for (a in (blockX - radius)..(blockX + radius))
			for (b in (blockY - radius)..(blockY + radius))
				for (c in (blockZ - radius)..(blockZ + radius)) {
					val d = (blockX - a) * (blockX - a) + (blockY - b) * (blockY - b) + (blockZ - c) * (blockZ - c)
					if (d < radius) {
						locs += Location(world, a.toDouble(), b.toDouble(), c.toDouble())
					}
				}
		return locs
	}

}
