package com.zivilon.cinder_loe.mixins;

import com.zivilon.cinder_loe.CinderLoE;
import com.zivilon.cinder_loe.util.Pair;
import com.zivilon.cinder_loe.util.DamageEvent;
import com.zivilon.cinder_loe.util.IMixinEntityPlayer;
import com.zivilon.cinder_loe.potion.LoEPotions;
import com.zivilon.cinder_loe.potion.PotionHerbPoison;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.*;
import net.minecraft.entity.boss.EntityDragonPart;
import net.minecraft.entity.effect.EntityLightningBolt;
import net.minecraft.entity.player.*;
import net.minecraft.entity.projectile.EntityFishHook;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.InventoryEnderChest;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.stats.*;
import net.minecraft.util.*;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World;
import net.minecraft.enchantment.EnchantmentHelper;

import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.ISpecialArmor.ArmorProperties;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.AttackEntityEvent;

import com.mojang.authlib.GameProfile;

import java.util.HashMap;
import java.util.List;

@Mixin(EntityPlayer.class)
public abstract class MixinEntityPlayer extends EntityLivingBase implements IMixinEntityPlayer {
    public int last_pickpocket_attempt = 0;

    public MixinEntityPlayer(World world, GameProfile p_i45324_2_) {
        super(world);
    }

    @Shadow(remap = false)
    public static final String PERSISTED_NBT_TAG = "PlayerPersisted";
    @Shadow(remap = false)
    private HashMap<Integer, ChunkCoordinates> spawnChunkMap;
    @Shadow(remap = false)
    private HashMap<Integer, Boolean> spawnForcedMap;
    @Shadow
    public InventoryPlayer inventory;
    @Shadow
    private InventoryEnderChest theInventoryEnderChest;
    @Shadow
    public Container inventoryContainer;
    @Shadow
    public Container openContainer;
    @Shadow
    protected FoodStats foodStats;
    @Shadow
    protected int flyToggleTimer;
    @Shadow
    public float prevCameraYaw;
    @Shadow
    public float cameraYaw;
    @Shadow
    public int xpCooldown;
    @Shadow
    protected boolean sleeping;
    @Shadow
    public ChunkCoordinates playerLocation;
    @Shadow
    private int sleepTimer;
    @Shadow
    private ChunkCoordinates spawnChunk;
    @Shadow
    private boolean spawnForced;
    @Shadow
    private ChunkCoordinates startMinecartRidingCoordinate;
    @Shadow
    public PlayerCapabilities capabilities;
    @Shadow
    public int experienceLevel;
    @Shadow
    public int experienceTotal;
    @Shadow
    public float experience;
    @Shadow
    private ItemStack itemInUse;
    @Shadow
    private int itemInUseCount;
    @Shadow
    protected float speedOnGround;
    @Shadow
    protected float speedInAir;
    @Shadow
    public EntityFishHook fishEntity;
    @Shadow
    public void destroyCurrentEquippedItem() {}
    @Shadow
    public void addStat(StatBase p_71064_1_, int p_71064_2_) {}
    @Shadow
    public ItemStack getCurrentEquippedItem() { return null;}
    @Shadow
    public void onEnchantmentCritical(Entity p_71047_1_) {}
    @Shadow
    public void onCriticalHit(Entity p_71009_1_) {}
    @Shadow
    public void triggerAchievement(StatBase p_71029_1_) {}
    @Shadow
    public abstract void addExhaustion(float p_71020_1_);

    /**
    * @author Shinare
    * @reason Removed vanilla blocking damage reduction
    */
    @Overwrite
    protected void damageEntity(DamageSource source, float damage) {
        if (!this.isEntityInvulnerable())
        {
            damage = ForgeHooks.onLivingHurt(this, source, damage);
            if (damage <= 0) return;

            damage = ArmorProperties.ApplyArmor(this, inventory.armorInventory, source, damage);
            if (damage <= 0) return;
            damage = this.applyPotionDamageCalculations(source, damage);
            float f1 = damage;
            damage = Math.max(damage - this.getAbsorptionAmount(), 0.0F);
            this.setAbsorptionAmount(this.getAbsorptionAmount() - (f1 - damage));

            if (damage != 0.0F)
            {
                this.addExhaustion(source.getHungerDamage());
                float f2 = this.getHealth();
                this.setHealth(this.getHealth() - damage);
                this.func_110142_aN().func_94547_a(source, f2, damage);
            }
        }
    }
    @Override
    public void set_last_pickpocket_attempt(int i) {
        this.last_pickpocket_attempt = i;
    }
    @Override
    public int get_last_pickpocket_attempt() {
        return this.last_pickpocket_attempt;
    }

    /**
     * @author Shinare
     * @reason Made critical hits not occur if overdosed
     */
    @Overwrite
    public void attackTargetEntityWithCurrentItem(Entity p_71059_1_)
    {
        if (MinecraftForge.EVENT_BUS.post(new AttackEntityEvent(((EntityPlayer)(Object)this), p_71059_1_)))
        {
            return;
        }
        ItemStack stack = getCurrentEquippedItem();
        if (stack != null && stack.getItem().onLeftClickEntity(stack, ((EntityPlayer)(Object)this), p_71059_1_))
        {
            return;
        }
        if (p_71059_1_.canAttackWithItem())
        {
            if (!p_71059_1_.hitByEntity(this))
            {
                float f = (float)this.getEntityAttribute(SharedMonsterAttributes.attackDamage).getAttributeValue();
                int i = 0;
                float f1 = 0.0F;

                if (p_71059_1_ instanceof EntityLivingBase)
                {
                    f1 = EnchantmentHelper.getEnchantmentModifierLiving(this, (EntityLivingBase)p_71059_1_);
                    i += EnchantmentHelper.getKnockbackModifier(this, (EntityLivingBase)p_71059_1_);
                }

                if (this.isSprinting())
                {
                    ++i;
                }

                if (f > 0.0F || f1 > 0.0F)
                {
                    boolean flag = this.fallDistance > 0.0F && !this.onGround && !this.isOnLadder() && !this.isInWater() && !this.isPotionActive(Potion.blindness) && this.ridingEntity == null && p_71059_1_ instanceof EntityLivingBase;
                    if (PotionHerbPoison.should_cancel_crit((EntityPlayer)(Object)this)) {
                        flag = false;
                    }

                    if (flag && f > 0.0F)
                    {
                        f *= 1.5F;
                    }

                    f += f1;
                    boolean flag1 = false;
                    int j = EnchantmentHelper.getFireAspectModifier(((EntityPlayer)(Object)this));

                    if (p_71059_1_ instanceof EntityLivingBase && j > 0 && !p_71059_1_.isBurning())
                    {
                        flag1 = true;
                        p_71059_1_.setFire(1);
                    }

                    boolean flag2 = p_71059_1_.attackEntityFrom(DamageSource.causePlayerDamage(((EntityPlayer)(Object)this)), f);

                    if (flag2)
                    {
                        if (i > 0)
                        {
                            p_71059_1_.addVelocity((double)(-MathHelper.sin(this.rotationYaw * (float)Math.PI / 180.0F) * (float)i * 0.5F), 0.1D, (double)(MathHelper.cos(((EntityPlayer)(Object)this).rotationYaw * (float)Math.PI / 180.0F) * (float)i * 0.5F));
                            ((EntityPlayer)(Object)this).motionX *= 0.6D;
                            ((EntityPlayer)(Object)this).motionZ *= 0.6D;
                            ((EntityPlayer)(Object)this).setSprinting(false);
                        }

                        if (flag)
                        {
                            this.onCriticalHit(p_71059_1_);
                        }

                        if (f1 > 0.0F)
                        {
                            this.onEnchantmentCritical(p_71059_1_);
                        }

                        if (f >= 18.0F)
                        {
                            this.triggerAchievement(AchievementList.overkill);
                        }

                        ((EntityPlayer)(Object)this).setLastAttacker(p_71059_1_);

                        if (p_71059_1_ instanceof EntityLivingBase)
                        {
                            EnchantmentHelper.func_151384_a((EntityLivingBase)p_71059_1_, ((EntityPlayer)(Object)this));
                        }

                        EnchantmentHelper.func_151385_b(((EntityPlayer)(Object)this), p_71059_1_);
                        ItemStack itemstack = ((EntityPlayer)(Object)this).getCurrentEquippedItem();
                        Object object = p_71059_1_;

                        if (p_71059_1_ instanceof EntityDragonPart)
                        {
                            IEntityMultiPart ientitymultipart = ((EntityDragonPart)p_71059_1_).entityDragonObj;

                            if (ientitymultipart != null && ientitymultipart instanceof EntityLivingBase)
                            {
                                object = (EntityLivingBase)ientitymultipart;
                            }
                        }

                        if (itemstack != null && object instanceof EntityLivingBase)
                        {
                            itemstack.hitEntity((EntityLivingBase)object, ((EntityPlayer)(Object)this));

                            if (itemstack.stackSize <= 0)
                            {
                                ((EntityPlayer)(Object)this).destroyCurrentEquippedItem();
                            }
                        }

                        if (p_71059_1_ instanceof EntityLivingBase)
                        {
                            this.addStat(StatList.damageDealtStat, Math.round(f * 10.0F));

                            if (j > 0)
                            {
                                p_71059_1_.setFire(j * 4);
                            }
                        }

                        this.addExhaustion(0.3F);
                    }
                    else if (flag1)
                    {
                        p_71059_1_.extinguish();
                    }
                }
            }
        }
    }

    @Inject(method = "onLivingUpdate", at = @At("TAIL"))
    public void disableHotbarSlotsOverdose(CallbackInfo ci) {
        EntityPlayer player = (EntityPlayer)(Object)this;
        PotionEffect effect = player.getActivePotionEffect(LoEPotions.overdose);

        if (effect != null && effect.getAmplifier() >= 2) {
            int slot = player.inventory.currentItem;
            if (slot >= 3 && slot <= 8) {
                player.inventory.currentItem = 0;
            }
        }
    }
    public boolean canAttackWithItem() {
        EntityPlayer player = (EntityPlayer)(Object)this;
        PotionEffect effect = player.getActivePotionEffect(LoEPotions.overdose);

        if (effect != null && effect.getAmplifier() >= 2) {
            int slot = player.inventory.currentItem;
            if (slot >= 3 && slot <= 8) {
                return false;
            }
        }
        return super.canAttackWithItem();
    }
}
