package com.zivilon.cinder_loe;

import com.zivilon.cinder_loe.entity.corrupt.CorruptMan;
import com.zivilon.cinder_loe.entity.projectile.EntityElvenArrow;
import com.zivilon.cinder_loe.items.specials.BrokenHalo;
import com.zivilon.cinder_loe.network.PacketWarbandLocations;
import com.zivilon.cinder_loe.util.RangedDamageUtil;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.IFuelHandler;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import lotr.common.LOTRLevelData;
import lotr.common.LOTRMod;
import lotr.common.LOTRDimension;
import lotr.common.enchant.LOTREnchantment;
import lotr.common.enchant.LOTREnchantmentHelper;
import lotr.common.entity.item.LOTREntityArrowPoisoned;
import lotr.common.entity.npc.LOTREntityOrc;
import lotr.common.entity.projectile.LOTREntityCrossbowBolt;
import lotr.common.entity.projectile.LOTREntityDart;
import lotr.common.fac.LOTRFaction;
import lotr.common.item.*;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.item.*;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSourceIndirect;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.event.entity.player.ArrowLooseEvent;

import java.util.Random;

import static com.zivilon.cinder_loe.CinderLoE.getLOTRMaterialByName;

public class CinderEventHandler implements IFuelHandler {

    private static final ItemArmor.ArmorMaterial MATERIAL_GILDEDGALVORN =
            getLOTRMaterialByName("GILDEDGALVORN").toArmorMaterial();

    private static final Random random = new Random();
    public  CinderEventHandler() {
        FMLCommonHandler.instance().bus().register(this);
        MinecraftForge.EVENT_BUS.register(this);
        MinecraftForge.TERRAIN_GEN_BUS.register(this);
        GameRegistry.registerFuelHandler(this);
    }

    @SubscribeEvent
    public void onWorldTick(TickEvent.WorldTickEvent event) {
        World world = event.world;
        if (world.isRemote)
            return;
        if (event.phase == TickEvent.Phase.END) {
            if (world == DimensionManager.getWorld(LOTRDimension.MIDDLE_EARTH.dimensionID)) {
                if (!world.playerEntities.isEmpty()) {
                    if (world.getTotalWorldTime() % 20L == 0L) {
                        PacketWarbandLocations.send_warband_locations(world);
                    }
                }
            }
        }

    }

    @SubscribeEvent
    public void onArrowLoose(ArrowLooseEvent event) {
        Entity attacker = event.entityLiving;
        if (attacker instanceof EntityPlayerMP player) {
            ItemStack bow = player.getHeldItem();
            if (bow != null && bow.isItemStackDamageable() && (bow.getItem() instanceof LOTRItemBow || bow.getItem() instanceof ItemBow)) {
                float[] durabilityThresholds = {0.5f, 0.4f, 0.25f};
                double[] probabilities = {0.0005, 0.001, 0.005}; // Corrected probabilities

                // Corrected durabilityPercent calculation
                float durabilityPercent = (float) (bow.getMaxDamage() - bow.getItemDamage()) / bow.getMaxDamage();

                for (int j = 0; j < durabilityThresholds.length; j++) {
                    if (durabilityPercent <= durabilityThresholds[j] && random.nextDouble() <= probabilities[j]) {
                        addNegativeModifier(bow, player, "bow");
                        break; // Exit loop once a modifier is added
                    }
                }
            }
        }
    }

    @SubscribeEvent
    public void onLivingAttack(LivingAttackEvent event) {
        if (event.entityLiving.worldObj.isRemote) return;
        EntityLivingBase target = event.entityLiving;

        if (event.source instanceof EntityDamageSourceIndirect) {
            Entity proj = event.source.getSourceOfDamage();
            if (proj instanceof EntityArrow
                    || proj instanceof LOTREntityCrossbowBolt
                    || proj instanceof LOTREntityDart) {
                boolean allGalvorn = true;
                for (int slot = 1; slot <= 4; slot++) {
                    ItemStack armor = target.getEquipmentInSlot(slot);
                    if (armor == null
                            || !(armor.getItem() instanceof ItemArmor)
                            || ((ItemArmor)armor.getItem()).getArmorMaterial()
                            != CinderLoE.MATERIAL_GILDEDGALVORN.toArmorMaterial()) {
                        allGalvorn = false;
                        break;
                    }
                }
                if (allGalvorn && target instanceof EntityPlayerMP) {
                    ((EntityPlayerMP)target).inventory.damageArmor(event.ammount);
                    cancelAttackEvent(event);
                    return;
                }
            }
        }

        Entity rawAttacker = event.source.getEntity();

        if (!(rawAttacker instanceof EntityPlayerMP)) return;
        EntityPlayerMP player = (EntityPlayerMP) rawAttacker;

        ItemStack held = player.getHeldItem();
        if (held != null) {
            if (held.getItem() == LOTRMod.maceMallornCharred
                    && LOTRLevelData.getData(player).getAlignment(LOTRFaction.FANGORN) > 0) {
                player.addPotionEffect(new PotionEffect(Potion.weakness.id, 100));
                String msg = EnumChatFormatting.RED
                        + "Your hand grows weak the "
                        + EnumChatFormatting.YELLOW
                        + "Ents of Fangorn"
                        + EnumChatFormatting.RED
                        + " do not forgive you!";
                player.addChatMessage(new ChatComponentText(msg));
                player.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "You must have negative Fangorn alignment."));
            } else if (held.getItem() == LOTRMod.swordGondolin
                    && LOTRLevelData.getData(player).getAlignment(LOTRFaction.ANGMAR) > 0) {
                player.addPotionEffect(new PotionEffect(Potion.weakness.id, 100));
                String msg = EnumChatFormatting.RED
                        + "Your hand grows weak the "
                        + EnumChatFormatting.YELLOW
                        + "Gondolininian spirits"
                        + EnumChatFormatting.RED
                        + " do not forgive you!";
                player.addChatMessage(new ChatComponentText(msg));
                player.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "You must have negative Angmar alignment."));
            }
        }


        if (held != null) {
            boolean isMelee = held.getItem() instanceof LOTRItemSpear
                    || held.getItem() instanceof LOTRItemSword
                    || held.getItem() instanceof LOTRItemDagger
                    || held.getItem() instanceof LOTRItemBattleaxe
                    || held.getItem() instanceof LOTRItemHammer
                    || held.getItem() instanceof ItemSword;
            if (isMelee && held.isItemStackDamageable()) {
                float pct = (held.getMaxDamage() - held.getItemDamage()) / (float) held.getMaxDamage();
                float[] thresholds = {0.5f, 0.4f, 0.25f};
                double[] probs     = {0.0005, 0.001, 0.005};
                for (int i = 0; i < thresholds.length; i++) {
                    if (pct <= thresholds[i] && random.nextDouble() <= probs[i]) {
                        addNegativeModifier(held, player, "weapon");
                        break;
                    }
                }
            }
        }
    }


    private void cancelAttackEvent(LivingAttackEvent event) {
        event.setCanceled(true);
        DamageSource source = event.source;
        if (source instanceof EntityDamageSourceIndirect) {
            Entity entity = source.getSourceOfDamage();
        }
    }
    @SubscribeEvent
    public void onLivingHurt(LivingHurtEvent event) {

        if (event.entityLiving == null || event.source.getEntity() == null) return;

        EntityLivingBase entity = event.entityLiving;
        EntityLivingBase attacker = event.source.getEntity() instanceof EntityLivingBase ? (EntityLivingBase) event.source.getEntity() : null;
        World world = entity.worldObj;
        DamageSource source = event.source;



        if (event.source.getSourceOfDamage() instanceof LOTREntityArrowPoisoned && !world.isRemote) {
            LOTREntityArrowPoisoned arrow = (LOTREntityArrowPoisoned) event.source.getSourceOfDamage();
            Entity shooter = arrow.shootingEntity;
            if (!(shooter instanceof EntityPlayerMP)) return;
            EntityPlayerMP player = (EntityPlayerMP) shooter;
            ItemStack item = player.inventory.getCurrentItem();
            if (item == null || item.getItem() != CinderLoE.bowLurtz) return;
            event.setCanceled(true);
            if (entity.isPotionActive(Potion.poison.id)) entity.removePotionEffect(Potion.poison.id);
            entity.addPotionEffect(new PotionEffect(LOTRPoisonedDrinks.killingPoison.id, 100));
        }

        //Elven Arrow, deals more damage to orc kind
        // Utilizing the new Util, test if it works!
        if (!world.isRemote && entity instanceof LOTREntityOrc && event.source.getSourceOfDamage() instanceof EntityElvenArrow) {
            RangedDamageUtil.applyExtraDamage(event, 0.2f);  // increase damage by 20%
        }

        // Negative Arrow Protection Handler
        if (!event.entityLiving.worldObj.isRemote && event.source.isProjectile() && event.entityLiving instanceof EntityPlayerMP player) {

            float totalAdditionalDamage = 0.0f; // Initialize total additional damage

            for (int i = 0; i < 4; i++) {
                ItemStack armor = player.getEquipmentInSlot(i + 1);
                if (armor != null) {
                    LOTREnchantment protectRangedWeak1 = LOTREnchantment.getEnchantmentByName("protectRangedWeak1");
                    LOTREnchantment protectRangedWeak2 = LOTREnchantment.getEnchantmentByName("protectRangedWeak2");

                    if (LOTREnchantmentHelper.hasEnchant(armor, protectRangedWeak1)) {
                        float additionalDamage = 0.2f; // 20% more damage per piece
                        totalAdditionalDamage += additionalDamage; // Accumulate damage increase
                    }
                    if (LOTREnchantmentHelper.hasEnchant(armor, protectRangedWeak2)) {
                        float additionalDamage = 0.4f; // 40% more damage per piece
                        totalAdditionalDamage += additionalDamage; // Accumulate damage increase
                    }
                }
            }

            // Apply total additional damage
            if (totalAdditionalDamage > 0) {
                float newDamage = event.ammount * (1 + totalAdditionalDamage); // Calculate new damage
                float newHealth = player.getHealth() - (newDamage - event.ammount); // Calculate health after applying extra damage

                if (newHealth > 0) {
                    player.setHealth(newHealth);
                    event.setCanceled(true);
                } else {
                    event.ammount = player.getHealth(); // Ensure player dies if health reaches 0 or below
                }

            }
        }

        // Broken Halo Event handler, Unused, deprecated until the halo has a new usage
//        if (attacker != null && event.source.getSourceOfDamage() == attacker) {
//            ItemStack helmet = entity.getEquipmentInSlot(4);
//            if (helmet != null && helmet.getItem() instanceof BrokenHalo) {
//
//                if (random.nextDouble() <= 0.25) {
//                    // Summon Corrupt Civilian NPC
//                    CorruptMan spawnedEntity = new CorruptMan(world);
//                    spawnedEntity.copyLocationAndAnglesFrom(attacker);
//
//                    // Randomly select main weapon
//                    ItemStack mainWeapon = getRandomWeapon();
//                    spawnedEntity.npcItemsInv.setIdleItem(mainWeapon);
//                    spawnedEntity.npcItemsInv.setMeleeWeapon(mainWeapon);
//                    spawnedEntity.setHealth(10);
//                    spawnedEntity.addPotionEffect(new PotionEffect(Potion.regeneration.id, 9999, 0));
//
//                    spawnedEntity.onSpawnWithEgg(null);
//                    world.spawnEntityInWorld(spawnedEntity);
//                    world.playAuxSFXAtEntity(null, 1016, (int) spawnedEntity.posX, (int) spawnedEntity.posY, (int) spawnedEntity.posZ, 0);
//                    world.playSoundAtEntity(entity, "mob.zombie.unfect", 1F, 1F);
//
//                }
//            }
//        }

        // Smithing Rework event handler

        if (entity instanceof EntityPlayerMP player) {

            // Durability thresholds and corresponding probabilities for adding a negative modifier
            float[] durabilityThresholds = {0.4f, 0.3f, 0.2f};
            double[] probabilities        = {0.0005, 0.001, 0.005};
            LOTREnchantment sturdyArmor   = LOTREnchantment.getEnchantmentByName("armorSturdy");

            for (int slot = 1; slot <= 4; slot++) {
                ItemStack armor = player.getEquipmentInSlot(slot);
                if (armor == null || !armor.isItemStackDamageable()) continue;

                float durabilityPercent = (armor.getMaxDamage() - armor.getItemDamage()) / (float)armor.getMaxDamage();
                boolean hasSturdy      = LOTREnchantmentHelper.hasEnchant(armor, sturdyArmor);

                for (int i = 0; i < durabilityThresholds.length; i++) {
                    if (durabilityPercent <= durabilityThresholds[i]) {
                        double chance = probabilities[i] * (hasSturdy ? 0.5 : 1.0);
                        if (random.nextDouble() <= chance) {
                            addNegativeModifier(armor, player, "armor");
                        }
                        break;
                    }
                }
            }

        }

        // Isildurs chestplate handler
        // Incoming damage from poison, drink poison (for lurtz bow, rip anyone who drinks a bad drink), or wither is doubled

        if (event.entityLiving.worldObj.isRemote) return;
        if (!(event.entityLiving instanceof EntityPlayerMP)) return;

        EntityPlayerMP player = (EntityPlayerMP) event.entityLiving;
        ItemStack chest = player.getEquipmentInSlot(2);
        if (chest == null || chest.getItem() != CinderLoE.bodyIsildur) return;

        boolean isDrinkPoison = player.isPotionActive(LOTRPoisonedDrinks.killingPoison.id);
        boolean isWither    = event.source == DamageSource.wither;
        if (isDrinkPoison || isWither) {
            event.ammount *= 2.0F;
        }
    }

    private void sendNegativeModifierMessage(EntityPlayerMP player, String type) {
        player.addChatMessage(new ChatComponentText(
                EnumChatFormatting.RED + "Your " +
                EnumChatFormatting.GOLD + type +
                EnumChatFormatting.RED + " has received a negative modifier!"
        ));
    }
    private void playNegativeModifierSound(World world, double x, double y, double z) {
        world.playSoundEffect(x, y, z, "mob.irongolem.hit", 1.0F, 2.0F);
    }
    private void addNegativeModifier(ItemStack item, EntityPlayerMP player, String type) {
        //Sturdy Check
        LOTREnchantment sturdy = type.equals("weapon") || type.equals("bow")
                ? LOTREnchantment.getEnchantmentByName("meleeSturdy")
                : type.equals("armor")
                ? LOTREnchantment.getEnchantmentByName("armorSturdy")
                : null;

        if (sturdy != null && LOTREnchantmentHelper.hasEnchant(item, sturdy))
            return;

        NBTTagCompound tag = item.getTagCompound();
        if (tag == null) {
            tag = new NBTTagCompound();
            item.setTagCompound(tag);
        }

        if (!tag.hasKey("LOTREnch")) {
            tag.setTag("LOTREnch", new NBTTagList());
        }

        NBTTagList enchList = tag.getTagList("LOTREnch", 8); // 8 is the type for strings
        boolean protectWeakUpgraded = false;
        boolean protectRangedWeakUpgraded = false;
        boolean upgraded = false;

        boolean meleeSwift = false;
        boolean meleeReach = false;

        if (type.equals("armor")) {
            // First, iterate and upgrade if necessary
            for (int i = 0; i < enchList.tagCount(); i++) {
                String ench = enchList.getStringTagAt(i);
                switch (ench) {
                    case "protectWeak1" -> {
                        enchList.removeTag(i);
                        enchList.appendTag(new NBTTagString("protectWeak2"));
                        protectWeakUpgraded = true;
                        i--; // Adjust index after removal
                        playNegativeModifierSound(player.worldObj, player.posX, player.posY, player.posZ);
                        sendNegativeModifierMessage(player, "Armor");
                    }
                    case "protectRangedWeak1" -> {
                        enchList.removeTag(i);
                        enchList.appendTag(new NBTTagString("protectRangedWeak2"));
                        protectRangedWeakUpgraded = true;
                        i--; // Adjust index after removal
                        playNegativeModifierSound(player.worldObj, player.posX, player.posY, player.posZ);
                        sendNegativeModifierMessage(player, "Armor");
                    }
                    case "protectWeak2" -> protectWeakUpgraded = true;
                    case "protectRangedWeak2" -> protectRangedWeakUpgraded = true;
                }
            }
            // After upgrading, check if we need to add a new modifier
            if (!protectWeakUpgraded || !protectRangedWeakUpgraded) {
                // Separate conditions for adding new modifiers
                if (!protectWeakUpgraded && !protectRangedWeakUpgraded) {
                    // Randomly add either protectWeak1 or protectRangedWeak1
                    String[] possibleModifiers = {"protectWeak1", "protectRangedWeak1"};
                    String newModifier = possibleModifiers[random.nextInt(possibleModifiers.length)];
                    enchList.appendTag(new NBTTagString(newModifier));
                } else if (!protectWeakUpgraded) {
                    // Only protectWeak1 is added
                    enchList.appendTag(new NBTTagString("protectWeak1"));
                } else if (!protectRangedWeakUpgraded) {
                    // Only protectRangedWeak1 is added
                    enchList.appendTag(new NBTTagString("protectRangedWeak1"));
                }
                playNegativeModifierSound(player.worldObj, player.posX, player.posY, player.posZ);
                sendNegativeModifierMessage(player, "Armor");
            }

            tag.setTag("LOTREnch", enchList);
        } else if (type.equals("bow")) {
            for (int i = 0; i < enchList.tagCount(); i++) {
                String ench = enchList.getStringTagAt(i);
                switch (ench) {
                    case "rangedWeak1" -> {
                        enchList.removeTag(i);
                        enchList.appendTag(new NBTTagString("rangedWeak2"));
                        upgraded = true;
                        i--; // Adjust index after removal
                        playNegativeModifierSound(player.worldObj, player.posX, player.posY, player.posZ);
                        sendNegativeModifierMessage(player, "Bow");
                    }
                    case "rangedWeak2" -> {
                        enchList.removeTag(i);
                        enchList.appendTag(new NBTTagString("rangedWeak3"));
                        upgraded = true;
                        i--; // Adjust index after removal
                        playNegativeModifierSound(player.worldObj, player.posX, player.posY, player.posZ);
                        sendNegativeModifierMessage(player, "Bow");
                    }
                    case "rangedWeak3" -> upgraded = true;
                }
            }
            if (!upgraded) {
                // Randomly add either rangedWeak1... etc
                String[] possibleModifiers = {"rangedWeak1", "rangedWeak2", "rangedWeak3"};
                String newModifier = possibleModifiers[random.nextInt(possibleModifiers.length)];
                enchList.appendTag(new NBTTagString(newModifier));
                playNegativeModifierSound(player.worldObj, player.posX, player.posY, player.posZ);
                sendNegativeModifierMessage(player, "Weapon");
            }
        } else if (type.equals("weapon")) {
            // First, iterate and upgrade if necessary
            for (int i = 0; i < enchList.tagCount(); i++) {
                String ench = enchList.getStringTagAt(i);
                switch (ench) {
                    case "weak1" -> {
                        enchList.removeTag(i);
                        enchList.appendTag(new NBTTagString("weak2"));
                        upgraded = true;
                        i--; // Adjust index after removal
                        playNegativeModifierSound(player.worldObj, player.posX, player.posY, player.posZ);
                        sendNegativeModifierMessage(player, "Weapon");
                    }
                    case "weak3" -> {
                        enchList.removeTag(i);
                        enchList.appendTag(new NBTTagString("weak4"));
                        upgraded = true;
                        i--; // Adjust index after removal
                        playNegativeModifierSound(player.worldObj, player.posX, player.posY, player.posZ);
                        sendNegativeModifierMessage(player, "Weapon");
                    }
                    case "weak4" -> upgraded = true;
                    case "meleeSlow1" -> meleeSwift = true;
                    case "meleeUnreach1" -> meleeReach = true;
                }
            }
            // After upgrading, check if we need to add a new modifier
            if (!upgraded || !meleeSwift || !meleeReach) {
                // Separate conditions for adding new modifiers
                if (!upgraded && !meleeSwift && !meleeReach) {
                    // Randomly add one of the possible modifiers
                    String[] possibleModifiers = {"weak1", "weak2", "weak3", "weak4", "meleeSlow1", "meleeUnreach1"};
                    String newModifier = possibleModifiers[random.nextInt(possibleModifiers.length)];
                    enchList.appendTag(new NBTTagString(newModifier));
                } else if (!upgraded) {
                    // Only weak modifier is added
                    String[] weakModifiers = {"weak1", "weak2", "weak3", "weak4"};
                    String newModifier = weakModifiers[random.nextInt(weakModifiers.length)];
                    enchList.appendTag(new NBTTagString(newModifier));
                } else if (!meleeSwift) {
                    // Only meleeSlow1 is added
                    enchList.appendTag(new NBTTagString("meleeSlow1"));
                } else if (!meleeReach) {
                    // Only meleeUnreach1 is added
                    enchList.appendTag(new NBTTagString("meleeUnreach1"));
                }

                playNegativeModifierSound(player.worldObj, player.posX, player.posY, player.posZ);
                sendNegativeModifierMessage(player, "Weapon");
            }


            tag.setTag("LOTREnch", enchList);
        }
    }



    private ItemStack getRandomWeapon() {
        Item[] weapons = new Item[]{LOTRMod.blacksmithHammer, LOTRMod.daggerIron, LOTRMod.dunlendingTrident, LOTRMod.battleaxeBronze, CinderLoE.cleaver};
        return new ItemStack(weapons[random.nextInt(weapons.length)]);
    }

    @Override
    public int getBurnTime(ItemStack fuel) {
        return 0;
    }
}
