package com.zivilon.cinder_loe.mixins;

import com.zivilon.cinder_loe.util.Utilities;
import com.zivilon.cinder_loe.CinderLoE_Config;

import lotr.common.entity.npc.LOTREntityNPC;
import lotr.common.entity.npc.LOTRHiredNPCInfo;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.IAttribute;
import net.minecraft.entity.ai.attributes.IAttributeInstance;
import net.minecraft.entity.ai.attributes.RangedAttribute;
import net.minecraft.entity.item.EntityFireworkRocket;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.IChatComponent;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;

import java.util.UUID;
import java.lang.reflect.Method;

@Mixin(LOTRHiredNPCInfo.class)
public abstract class MixinLOTRHiredNPCInfo {

    private static UUID LEVEL_HEALTH_UUID = UUID.fromString("11111111-0000-0000-0000-000000000000");
    private static UUID LEVEL_DAMAGE_UUID = UUID.fromString("22222222-0000-0000-0000-000000000000");
    private static UUID LEVEL_MOVEMENT_UUID = UUID.fromString("33333333-0000-0000-0000-000000000000");
    private static double HEALTH_PER_UPGRADE = 1.0D;
    private static double DAMAGE_PER_UPGRADE = 0.25D;
    private static double SPEED_PER_UPGRADE = 0.0025D;

    @Shadow(remap = false)
    private LOTREntityNPC theEntity;
    @Shadow(remap = false)
    private UUID hiringPlayerUUID;
    @Shadow(remap = false)
    public int xpLevel = 1;
    @Shadow(remap = false)
    private boolean canMove;

    @Shadow(remap = false)
    public void sendClientPacket(boolean shouldOpenGui) {}

    /**
     * @author KeyLime17
     * @reason
     */
    @Overwrite(remap = false)
    public void onLevelUp() {
        EntityPlayer hirer;
        rotateLevelUpStat();

        Entity mount = this.theEntity.ridingEntity;
        if (mount instanceof EntityLivingBase && !(mount instanceof LOTREntityNPC)) {
            this.addLevelUpHealthGain((EntityLivingBase)mount);
        }
        if ((hirer = this.getHiringPlayer()) != null) {
            hirer.addChatMessage((IChatComponent)new ChatComponentTranslation("lotr.hiredNPC.levelUp", new Object[]{this.theEntity.getCommandSenderName(), this.xpLevel}));
        }
        this.spawnLevelUpFireworks();
    }


    public void rotateLevelUpStat() {
        LOTREntityNPC entity = this.theEntity;

        switch (entity.hiredNPCInfo.xpLevel % 3) {
            case 0:
                // +1 HP
                this.addLevelUpHealthGain(entity);
                break;
            case 1:
                // +0.25 Damage
                this.increaseDamageGain(entity);
                break;
            case 2:
                // +0.005 movement Speed
                this.increaseMovementGain(entity);
                break;
        }
    }

    /**
     * @author KeyLime17
     * @reason
     */
    @SuppressWarnings("OverwriteModifiers")
    @Overwrite(remap = false)
    public void addLevelUpHealthGain(EntityLivingBase entity) {
        IAttributeInstance attr = entity.getEntityAttribute(SharedMonsterAttributes.maxHealth);
        Utilities.increment_modifier(attr, LEVEL_HEALTH_UUID, "levelup_health", HEALTH_PER_UPGRADE, 0);
        entity.heal(1.0f);
    }

    public void increaseDamageGain(EntityLivingBase entity) {
        IAttributeInstance attr = entity.getEntityAttribute(LOTREntityNPC.npcAttackDamageExtra);
        Utilities.increment_modifier(attr, LEVEL_DAMAGE_UUID, "levelup_damage", DAMAGE_PER_UPGRADE, 0);
    }

    public void increaseMovementGain(EntityLivingBase entity) {
        IAttributeInstance attr = entity.getEntityAttribute(SharedMonsterAttributes.movementSpeed);
        Utilities.increment_modifier(attr, LEVEL_MOVEMENT_UUID, "levelup_speed", SPEED_PER_UPGRADE, 0);
    }




    /**
     * @author KeyLime17
     * @reason
     */
    @Overwrite(remap = false)
    public EntityPlayer getHiringPlayer() {
        if (this.hiringPlayerUUID == null) {
            return null;
        }
        return this.theEntity.worldObj.func_152378_a(this.hiringPlayerUUID);
    }

    public void spawnLevelUpFireworks() {
        boolean bigLvlUp = this.xpLevel % 5 == 0;
        World world = this.theEntity.worldObj;
        ItemStack itemstack = new ItemStack(Items.fireworks);
        NBTTagCompound itemData = new NBTTagCompound();
        NBTTagCompound fireworkData = new NBTTagCompound();
        NBTTagList explosionsList = new NBTTagList();
        int explosions = 1;
        for (int l = 0; l < explosions; ++l) {
            NBTTagCompound explosionData = new NBTTagCompound();
            explosionData.setBoolean("Flicker", true);
            explosionData.setBoolean("Trail", bigLvlUp);
            int[] colors = new int[]{0xFF5500, this.theEntity.getFaction().getFactionColor()};
            explosionData.setIntArray("Colors", colors);
            boolean effectType = bigLvlUp;
            explosionData.setByte("Type", (byte)(effectType ? 1 : 0));
            explosionsList.appendTag((NBTBase)explosionData);
        }
        fireworkData.setTag("Explosions", (NBTBase)explosionsList);
        itemData.setTag("Fireworks", (NBTBase)fireworkData);
        itemstack.setTagCompound(itemData);
        EntityFireworkRocket firework = new EntityFireworkRocket(world, this.theEntity.posX, this.theEntity.boundingBox.minY + (double)this.theEntity.height, this.theEntity.posZ, itemstack);
        NBTTagCompound fireworkNBT = new NBTTagCompound();
        firework.writeEntityToNBT(fireworkNBT);
        fireworkNBT.setInteger("LifeTime", bigLvlUp ? 20 : 15);
        firework.readEntityFromNBT(fireworkNBT);
        world.spawnEntityInWorld((Entity)firework);
    }

    /**
     * @author KeyLime17
     * @reason
     */
    @Overwrite(remap = false)
    public void ready() {
        this.canMove = true;
        if (CinderLoE_Config.unit_conversion_enabled) convert_stats();
        sendClientPacket(false);
    }

    public void convert_stats() {
        LOTREntityNPC entity = this.theEntity;
        Utilities.reset_attributes(entity);
        int level = entity.hiredNPCInfo.xpLevel;
        int health_upgrades = (int)Math.ceil(level/3);
        int damage_upgrades = (int)Math.ceil((level-health_upgrades)/2);
        int speed_upgrades = level-health_upgrades-damage_upgrades;
        Utilities.set_modifier(entity.getEntityAttribute(SharedMonsterAttributes.maxHealth), LEVEL_HEALTH_UUID, "levelup_health", HEALTH_PER_UPGRADE*health_upgrades, 0);
        Utilities.set_modifier(entity.getEntityAttribute(LOTREntityNPC.npcAttackDamageExtra), LEVEL_DAMAGE_UUID, "levelup_damage", DAMAGE_PER_UPGRADE*damage_upgrades, 0);
        Utilities.set_modifier(entity.getEntityAttribute(SharedMonsterAttributes.movementSpeed), LEVEL_MOVEMENT_UUID, "levelup_speed", SPEED_PER_UPGRADE*speed_upgrades, 0);
    }
}
