package ru.dbotthepony.mc.otm.item.weapon

import net.minecraft.core.BlockPos
import net.minecraft.core.component.DataComponents
import net.minecraft.tags.BlockTags
import net.minecraft.world.entity.EquipmentSlotGroup
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.attributes.AttributeModifier
import net.minecraft.world.entity.ai.attributes.Attributes
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
import net.minecraft.world.item.component.ItemAttributeModifiers
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.state.BlockState
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent
import net.neoforged.neoforge.common.ItemAbilities
import net.neoforged.neoforge.common.ItemAbility
import net.neoforged.neoforge.common.ModConfigSpec
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.EnergyConsumerItem
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.capability.energy.getBarColor
import ru.dbotthepony.mc.otm.capability.energy.getBarWidth
import ru.dbotthepony.mc.otm.capability.matteryEnergy
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.core.damageType
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue
import ru.dbotthepony.mc.otm.core.math.defineDecimal
import ru.dbotthepony.mc.otm.core.math.nextVariance
import ru.dbotthepony.mc.otm.core.otmRandom
import ru.dbotthepony.mc.otm.core.util.WriteOnce
import ru.dbotthepony.mc.otm.item.MatteryItem
import ru.dbotthepony.mc.otm.item.addSimpleDescription
import ru.dbotthepony.mc.otm.registry.CapabilitiesRegisterListener
import ru.dbotthepony.mc.otm.registry.MDamageTypes
import ru.dbotthepony.mc.otm.registry.MatteryDamageSource

class FallingSunItem : MatteryItem(Properties().stacksTo(1).rarity(Rarity.EPIC)), CapabilitiesRegisterListener {
	private val chargedAttributes: ItemAttributeModifiers
	private val dischargedAttributes: ItemAttributeModifiers

	init {
		var builder = ItemAttributeModifiers.builder()

		builder.add(Attributes.ATTACK_DAMAGE, AttributeModifier(BASE_ATTACK_DAMAGE_ID, 13.0, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND)
		builder.add(Attributes.ATTACK_SPEED, AttributeModifier(BASE_ATTACK_SPEED_ID, -3.4, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND)
		builder.add(Attributes.SWEEPING_DAMAGE_RATIO, AttributeModifier(ResourceLocation(OverdriveThatMatters.MOD_ID, "energy_sword_sweeping_edge"), 1.0, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND)

		chargedAttributes = builder.build()
		builder = ItemAttributeModifiers.builder()

		builder.add(Attributes.ATTACK_DAMAGE, AttributeModifier(BASE_ATTACK_DAMAGE_ID, 5.5, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND)
		builder.add(Attributes.ATTACK_SPEED, AttributeModifier(BASE_ATTACK_SPEED_ID, -3.4, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND)
		dischargedAttributes = builder.build()
	}

	override fun isEnchantable(p_41456_: ItemStack): Boolean {
		return p_41456_.count == 1
	}

	override fun getEnchantmentValue(stack: ItemStack): Int {
		return 12
	}

	override fun getDestroySpeed(itemStack: ItemStack, blockState: BlockState): Float {
		val energy = itemStack.getCapability(MatteryCapability.ITEM_ENERGY) ?: return 1f

		if (blockState.`is`(Blocks.COBWEB)) {
			return if (energy.batteryLevel < COBWEB_POWER_COST) 2f else 25f
		} else if (blockState.`is`(BlockTags.SWORD_EFFICIENT)) {
			return if (energy.batteryLevel < PLANT_POWER_COST) 1.5f else 8f
		} else {
			return 1f
		}
	}

	override fun canAttackBlock(p_41441_: BlockState, p_41442_: Level, p_41443_: BlockPos, p_41444_: Player): Boolean {
		return !p_41444_.isCreative
	}

	override fun hurtEnemy(itemStack: ItemStack, victim: LivingEntity, attacker: LivingEntity): Boolean {
		if (attacker is Player && attacker.isCreative) {
			victim.matteryPlayer?.let {
				if (it.isAndroid) {
					victim.invulnerableTime = 0
					victim.hurt(MatteryDamageSource(attacker.level().registryAccess().damageType(MDamageTypes.EMP), attacker, itemStack), 8f)
				}
			}

			return true
		}

		itemStack.getCapability(MatteryCapability.ITEM_ENERGY)?.let {
			if (it.extractEnergyExact(ENERGY_PER_SWING, false)) {
				it.extractEnergy(attacker.level().otmRandom.nextVariance(ENERGY_PER_SWING_VARIANCE), false)
				victim.matteryPlayer?.let {
					if (it.isAndroid && it.androidEnergy.extractEnergyExact(ENERGY_ZAP, false)) {
						it.androidEnergy.extractEnergy(attacker.level().otmRandom.nextVariance(ENERGY_ZAP_VARIANCE), false)
						victim.hurt(MatteryDamageSource(attacker.level().registryAccess().damageType(MDamageTypes.EMP), attacker, itemStack), 8f)
					}
				}
			}
		}

		return true
	}

	override fun isBarVisible(p_150899_: ItemStack): Boolean {
		return p_150899_.matteryEnergy != null
	}

	override fun getBarWidth(p_150900_: ItemStack): Int {
		return p_150900_.matteryEnergy?.getBarWidth() ?: super.getBarWidth(p_150900_)
	}

	override fun getBarColor(p_150901_: ItemStack): Int {
		return p_150901_.matteryEnergy?.getBarColor() ?: super.getBarColor(p_150901_)
	}

	init {
		tooltips.itemEnergy()

		addSimpleDescription()
		addSimpleDescription("2")
		addSimpleDescription("3")
		addSimpleDescription("4")
	}

	override fun mineBlock(
		itemStack: ItemStack,
		p_41417_: Level,
		blockState: BlockState,
		p_41419_: BlockPos,
		user: LivingEntity
	): Boolean {
		if (blockState.getDestroySpeed(p_41417_, p_41419_) > 0f && (user !is Player || !user.isCreative)) {
			val energy = itemStack.matteryEnergy

			if (blockState.`is`(BlockTags.SWORD_EFFICIENT)) {
				if (energy?.extractEnergyExact(PLANT_POWER_COST, false) == true)
					energy.extractEnergyExact(user.level().otmRandom.nextVariance(PLANT_POWER_COST_VARIANCE), false)
			}

			if (blockState.`is`(Blocks.COBWEB)) {
				if (energy?.extractEnergyExact(COBWEB_POWER_COST, false) == true)
					energy.extractEnergyExact(user.level().otmRandom.nextVariance(COBWEB_POWER_COST_VARIANCE), false)
			}
		}

		return true
	}

	override fun isCorrectToolForDrops(stack: ItemStack, state: BlockState): Boolean {
		val energy = stack.matteryEnergy ?: return super.isCorrectToolForDrops(stack, state)

		if (state.`is`(BlockTags.SWORD_EFFICIENT) && energy.batteryLevel >= PLANT_POWER_COST)
			return true
		else if (state.`is`(Blocks.COBWEB) && energy.batteryLevel >= COBWEB_POWER_COST)
			return true

		return super.isCorrectToolForDrops(stack, state)
	}

	private fun cap(stack: ItemStack) = EnergyConsumerItem(stack, MAX_ENERGY)

	override fun registerCapabilities(event: RegisterCapabilitiesEvent) {
		event.registerItem(MatteryCapability.ITEM_ENERGY, { o, _ -> cap(o) }, this)
		event.registerItem(Capabilities.EnergyStorage.ITEM, { o, _ -> cap(o) }, this)
	}

	override fun getDefaultAttributeModifiers(stack: ItemStack): ItemAttributeModifiers {
		val energy = cap(stack)

		if (energy.batteryLevel >= ENERGY_PER_SWING) {
			return chargedAttributes
		}

		return dischargedAttributes
	}

	override fun canPerformAction(stack: ItemStack, toolAction: ItemAbility): Boolean {
		if (cap(stack).extractEnergyExact(ENERGY_PER_SWING, true)) {
			return ItemAbilities.DEFAULT_SWORD_ACTIONS.contains(toolAction)
		}

		return false
	}

	companion object {
		val MAX_ENERGY get() = _MAX_ENERGY.get()
		val ENERGY_ZAP get() = _ENERGY_ZAP.get()
		val ENERGY_ZAP_VARIANCE get() = _ENERGY_ZAP_VARIANCE.get()
		val ENERGY_PER_SWING get() = _ENERGY_PER_SWING.get()
		val ENERGY_PER_SWING_VARIANCE get() = _ENERGY_PER_SWING_VARIANCE.get()
		val COBWEB_POWER_COST get() = _COBWEB_POWER_COST.get()
		val COBWEB_POWER_COST_VARIANCE get() = _COBWEB_POWER_COST_VARIANCE.get()
		val PLANT_POWER_COST get() = _PLANT_POWER_COST.get()
		val PLANT_POWER_COST_VARIANCE get() = _PLANT_POWER_COST_VARIANCE.get()

		private var _MAX_ENERGY: DecimalConfigValue by WriteOnce()
		private var _ENERGY_ZAP: DecimalConfigValue by WriteOnce()
		private var _ENERGY_ZAP_VARIANCE: DecimalConfigValue by WriteOnce()
		private var _ENERGY_PER_SWING: DecimalConfigValue by WriteOnce()
		private var _ENERGY_PER_SWING_VARIANCE: DecimalConfigValue by WriteOnce()
		private var _COBWEB_POWER_COST: DecimalConfigValue by WriteOnce()
		private var _COBWEB_POWER_COST_VARIANCE: DecimalConfigValue by WriteOnce()
		private var _PLANT_POWER_COST: DecimalConfigValue by WriteOnce()
		private var _PLANT_POWER_COST_VARIANCE: DecimalConfigValue by WriteOnce()

		fun registerConfig(builder: ModConfigSpec.Builder) {
			builder.comment("Falling Sun values").push("FallingSun")

			_MAX_ENERGY = builder.defineDecimal("MAX_ENERGY", Decimal(3_500_000), Decimal.ZERO)
			_ENERGY_ZAP = builder.comment("Extra energy required when hitting androids").defineDecimal("ENERGY_ZAP", Decimal(4_000), Decimal.ZERO)
			_ENERGY_ZAP_VARIANCE = builder.comment("Random deviation from ENERGY_ZAP").defineDecimal("ENERGY_ZAP_VARIANCE", Decimal(1200), Decimal.ZERO)
			_ENERGY_PER_SWING = builder.defineDecimal("ENERGY_PER_SWING", Decimal(3_000), Decimal.ZERO)
			_ENERGY_PER_SWING_VARIANCE = builder.comment("Random deviation from ENERGY_PER_SWING").defineDecimal("ENERGY_PER_SWING_VARIANCE", Decimal(600), Decimal.ZERO)
			_COBWEB_POWER_COST = builder.defineDecimal("COBWEB_POWER_COST", Decimal(2_500), Decimal.ZERO)
			_COBWEB_POWER_COST_VARIANCE = builder.comment("Random deviation from COBWEB_POWER_COST").defineDecimal("COBWEB_POWER_COST_VARIANCE", Decimal(500), Decimal.ZERO)
			_PLANT_POWER_COST = builder.defineDecimal("PLANT_POWER_COST", Decimal(500), Decimal.ZERO)
			_PLANT_POWER_COST_VARIANCE = builder.comment("Random deviation from PLANT_POWER_COST").defineDecimal("PLANT_POWER_COST_VARIANCE", Decimal(100), Decimal.ZERO)

			builder.pop()
		}
	}
}
