package com.zivilon.cinder_loe.mixins;

import com.zivilon.cinder_loe.entity.Renegade;
import com.zivilon.cinder_loe.potion.LoEPotions;
import com.zivilon.cinder_loe.util.IEntityLivingBase;
import com.zivilon.cinder_loe.util.Utilities;

import lotr.common.LOTRLevelData;
import lotr.common.LOTRMod;
import lotr.common.entity.ai.LOTREntityAINearestAttackableTargetBasic;
import lotr.common.entity.ai.LOTREntityAINearestAttackableTargetBasic.TargetSorter;
import lotr.common.entity.npc.LOTREntityNPC;
import lotr.common.entity.npc.LOTREntityNPCRideable;
import lotr.common.item.LOTRItemArmor;

import net.minecraft.command.IEntitySelector;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAITarget;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;

import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Collections;
import java.util.List;
import java.util.UUID;
import net.minecraft.util.ChatComponentText;
import lotr.common.enchant.LOTREnchantment;
import lotr.common.enchant.LOTREnchantmentHelper;

@Mixin(LOTREntityAINearestAttackableTargetBasic.class)
public abstract class MixinLOTREntityAINearestAttackableTargetBasic extends EntityAITarget {

    @Shadow(remap = false)
    private final Class targetClass;
    @Shadow(remap = false)
    private EntityLivingBase targetEntity;
    @Shadow(remap = false)
    private final TargetSorter targetSorter;
    @Shadow(remap = false)
    private final IEntitySelector targetSelector;
    @Shadow(remap = false)
    private final int targetChance;

    public MixinLOTREntityAINearestAttackableTargetBasic(EntityCreature p_i1669_1_, boolean p_i1669_2_) {
        super(p_i1669_1_, p_i1669_2_);
        targetClass = null;
        targetEntity = null;
        targetSorter = null;
        targetSelector = null;
        targetChance = 0;
    }

    /**
     * @author Shinare
     * @reason Made NPCs abandon targets if too far from warband leader
     */
    @Overwrite(remap = false)
    public boolean func_75250_a() { // shouldExecute()
        if (warband_should_execute()) return false;
        return original_should_execute();
    }

    private boolean warband_should_execute() {
        EntityCreature self = taskOwner;

        if (!(self instanceof IEntityLivingBase)) return false;

        UUID leader_id = ((IEntityLivingBase) self).get_warband_uuid();
        if (leader_id == null) return false;

        Entity leader = Utilities.find_entity_by_uuid(self.worldObj, leader_id);
        if (leader == null) return false;

        double distance_squared = self.getDistanceSqToEntity(leader);
        if (distance_squared > 576.0D) {
            self.setAttackTarget(null);
            self.getNavigator().tryMoveToEntityLiving(leader, 1.3D);
            return true;
        }
        return false;
    }
    public boolean original_should_execute() {
        if (this.targetChance > 0 && this.taskOwner.getRNG().nextInt(this.targetChance) != 0)
            return false;
        if (this.taskOwner instanceof LOTREntityNPC) {
            LOTREntityNPC npc = (LOTREntityNPC)this.taskOwner;
            if (npc.hiredNPCInfo.isActive && npc.hiredNPCInfo.isHalted())
                return false;
            if (npc.isChild())
                return false;
        }
        if (this.taskOwner instanceof LOTREntityNPCRideable) {
            LOTREntityNPCRideable rideable = (LOTREntityNPCRideable)this.taskOwner;
            if (rideable.isNPCTamed() || rideable.riddenByEntity instanceof EntityPlayer)
                return false;
        }
        double range = getTargetDistance();
        double rangeY = Math.min(range, 8.0D);
        List<?> entities = this.taskOwner.worldObj.selectEntitiesWithinAABB(this.targetClass, this.taskOwner.boundingBox.expand(range, rangeY, range), this.targetSelector);
        List<? extends Entity> entity_list = (List<? extends Entity>)entities;
        Collections.sort(entity_list, this.targetSorter);
        if (entities.isEmpty())
            return false;
        this.targetEntity = (EntityLivingBase)entities.get(0);
        return true;
    }

    /**
     * @author Shinare
     * @reason Added corrupting potion effect that makes all NPCs hostile
     */
    @Overwrite(remap = false)
    protected boolean isPlayerSuitableAlignmentTarget(EntityPlayer entityplayer) {
        float alignment = LOTRLevelData.getData(entityplayer).getAlignment(LOTRMod.getNPCFaction((Entity)this.taskOwner));
        if (entityplayer == null || LoEPotions.corrupting == null) return alignment < 0.0F;
        boolean corrupting = entityplayer.isPotionActive(LoEPotions.corrupting);
        return (alignment < 0.0F || corrupting);
    }

    @Inject(method = "isPlayerSuitableTarget", at = @At("HEAD"), cancellable = true, remap = false)
    private void cinderloe$applyStealthModifier(EntityPlayer player, CallbackInfoReturnable<Boolean> cir) {
        int stealthPieces = 0;

        for (ItemStack armor : player.inventory.armorInventory) {
            if (armor != null && armor.getItem() instanceof LOTRItemArmor && armor.stackTagCompound != null) {
                if (LOTREnchantmentHelper.hasEnchant(armor, LOTREnchantment.getEnchantmentByName("stealth"))) {
                    stealthPieces++;
                }
            }
        }

        if (stealthPieces > 0 && taskOwner != null) {
            double baseDetectionRange = taskOwner.getEntityAttribute(net.minecraft.entity.SharedMonsterAttributes.followRange).getAttributeValue();
            double multiplier = 1.0 - (0.15 * stealthPieces);
            double effectiveRangeSq = (baseDetectionRange * multiplier) * (baseDetectionRange * multiplier);
            double distanceSq = taskOwner.getDistanceSqToEntity(player);

            if (distanceSq > effectiveRangeSq) {
                cir.setReturnValue(false);
            }
        }
    }
}
