package thebetweenlands.common.item.equipment;

import java.util.List;

import javax.annotation.Nullable;

import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.client.renderer.RenderItem;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.texture.ITextureObject;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.client.event.EntityViewRenderEvent;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import thebetweenlands.api.capability.IEquipmentCapability;
import thebetweenlands.api.item.IEquippable;
import thebetweenlands.api.item.IRenamableItem;
import thebetweenlands.client.handler.WorldRenderHandler;
import thebetweenlands.client.tab.BLCreativeTabs;
import thebetweenlands.common.TheBetweenlands;
import thebetweenlands.common.capability.equipment.EnumEquipmentInventory;
import thebetweenlands.common.capability.equipment.EquipmentHelper;
import thebetweenlands.common.inventory.InventoryItem;
import thebetweenlands.common.inventory.InventoryPouch;
import thebetweenlands.common.item.EnumBLDyeColor;
import thebetweenlands.common.item.ITintedItem;
import thebetweenlands.common.proxy.CommonProxy;
import thebetweenlands.common.registries.CapabilityRegistry;
import thebetweenlands.common.registries.ItemRegistry;
import thebetweenlands.common.registries.KeyBindRegistry;

public class ItemLurkerSkinPouch extends Item implements IEquippable, IRenamableItem, ITintedItem {
    public ItemLurkerSkinPouch() {
        this.setMaxStackSize(1);
        this.setCreativeTab(BLCreativeTabs.GEARS);
        this.setMaxDamage(3);
        this.setNoRepair();

        this.addPropertyOverride(new ResourceLocation("pouch_size"), (stack, worldIn, entityIn) -> stack.getItemDamage());
        IEquippable.addEquippedPropertyOverrides(this);
    }

    /**
     * Returns the first accessible pouch of the players equipment (first priority) or hotbar
     *
     * @param player
     * @return
     */
    public static ItemStack getFirstPouch(EntityPlayer player) {
        IEquipmentCapability cap = player.getCapability(CapabilityRegistry.CAPABILITY_EQUIPMENT, null);
        if (cap != null) {
            IInventory inv = cap.getInventory(EnumEquipmentInventory.MISC);

            for (int i = 0; i < inv.getSizeInventory(); i++) {
                ItemStack stack = inv.getStackInSlot(i);
                if (!stack.isEmpty() && stack.getItem() == ItemRegistry.LURKER_SKIN_POUCH) {
                    return stack;
                }
            }
        }

        InventoryPlayer playerInventory = player.inventory;
        for (int i = 0; i < InventoryPlayer.getHotbarSize(); i++) {
            ItemStack stack = playerInventory.getStackInSlot(i);
            if (!stack.isEmpty() && stack.getItem() == ItemRegistry.LURKER_SKIN_POUCH) {
                return stack;
            }
        }

        return ItemStack.EMPTY;
    }

    @Override
    public int getMaxItemUseDuration(ItemStack stack) {
        return 1;
    }

    @Override
    public boolean showDurabilityBar(ItemStack stack) {
        return false;
    }
    
    @Override
    public boolean isRepairable() {
    	return false;
    }
    
    @Override
    public boolean getIsRepairable(ItemStack toRepair, ItemStack repair) {
    	return false;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> list, ITooltipFlag flagIn) {
        int slots = 9 + (stack.getItemDamage() * 9);
        list.add(TextFormatting.GRAY + I18n.format("tooltip.bl.lurker_skin_pouch.size", slots));
        list.add(I18n.format("tooltip.bl.lurker_skin_pouch.usage", KeyBindRegistry.OPEN_POUCH.getDisplayName()));
        if (stack.getItemDamage() < stack.getMaxDamage()) {
            list.add(I18n.format("tooltip.bl.lurker_skin_pouch.upgrade"));
        }
    }

    @Override
    public EnumActionResult onItemUseFirst(EntityPlayer player, World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ, EnumHand hand) {
    	if(player.isSneaking()) {
    		ItemStack heldItem = player.getHeldItem(hand);
    		if(!heldItem.isEmpty() && heldItem.getItem() == this) {
    			if(!world.isRemote) {
	    			InventoryItem inventory = new InventoryPouch(heldItem, 9 + (heldItem.getItemDamage() * 9), "Lurker Skin Pouch");
	    			TileEntity tile = world.getTileEntity(pos);
	        		if(tile != null) {
	        			IItemHandler itemHandler = tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side);
	        			if (itemHandler != null) {
                            for (int i = 0; i < inventory.getSizeInventory(); i++) {
                                ItemStack stack = inventory.getStackInSlot(i);
                                if (!stack.isEmpty()) {
                                    stack = ItemHandlerHelper.insertItemStacked(itemHandler, stack, false);
                                    inventory.setInventorySlotContents(i, stack);
                                }
                            }
                        }
	        		}
    			}
        		return EnumActionResult.SUCCESS;
    		}
    	}
    	return super.onItemUseFirst(player, world, pos, side, hitX, hitY, hitZ, hand);
    }
    
    @Override
    public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
        ItemStack stack = player.getHeldItem(hand);
        if (!world.isRemote) {
            if (!player.isSneaking()) {
            	checkForLegacyPouch(stack);
                player.openGui(TheBetweenlands.instance, CommonProxy.GUI_LURKER_POUCH, world, 0, 0, 0);
            } else {
                player.openGui(TheBetweenlands.instance, CommonProxy.GUI_ITEM_RENAMING, world, hand == EnumHand.MAIN_HAND ? 0 : 1, 0, 0);
            }
        }

        return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, stack);
    }

    private void checkForLegacyPouch(ItemStack stack) {
		if(!stack.hasTagCompound())
			stack.setTagCompound(new NBTTagCompound());
		if(!stack.getTagCompound().hasKey("type"))
			stack.getTagCompound().setInteger("type", 7);
	}

	@Override
	public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> items) {
		if(this.isInCreativeTab(tab)) {
			ItemStack basePouch = new ItemStack(this);
            items.add(basePouch);
            items.add(new ItemStack(this, 1, basePouch.getMaxDamage()));
        }
	}
    
    private static boolean isRenderingWorld;
    
    @SideOnly(Side.CLIENT)
    @SubscribeEvent
    public static void onFogColors(EntityViewRenderEvent.FogColors event) {
        isRenderingWorld = true;
    }

    @SideOnly(Side.CLIENT)
    @SubscribeEvent
    public static void onRenderWorldLast(RenderWorldLastEvent event) {
        isRenderingWorld = false;
    }
    
	@SideOnly(Side.CLIENT)
    @SubscribeEvent
	public static void onRenderPlayer(RenderLivingEvent.Specials.Post<EntityLivingBase> event) {
		if(event.getEntity() instanceof EntityPlayer) {
			renderPouch((EntityPlayer) event.getEntity(), event.getX(), event.getY(), event.getZ(), WorldRenderHandler.getPartialTicks());
		}
	}

	@SideOnly(Side.CLIENT)
	private static void renderPouch(EntityPlayer player, double x, double y, double z, float partialTicks) {
        IEquipmentCapability cap = player.getCapability(CapabilityRegistry.CAPABILITY_EQUIPMENT, null);
        if(cap != null) {
			IInventory inv = cap.getInventory(EnumEquipmentInventory.MISC);
			ItemStack pouch = ItemStack.EMPTY;

			for(int i = 0; i < inv.getSizeInventory(); i++) {
				ItemStack stack = inv.getStackInSlot(i);
				if(!stack.isEmpty() && stack.getItem() == ItemRegistry.LURKER_SKIN_POUCH) {
					pouch = stack;
					break;
				}
			}

			if(!pouch.isEmpty()) {
				TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
				RenderItem renderItem = Minecraft.getMinecraft().getRenderItem();

				textureManager.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
				ITextureObject texture = textureManager.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
				texture.setBlurMipmap(false, false);

				IBakedModel model = renderItem.getItemModelWithOverrides(pouch, null, null);

				GlStateManager.pushMatrix();
				GlStateManager.translate(x, y + 1.0D, z);
				if(!isRenderingWorld) {
					GlStateManager.rotate(90 - player.renderYawOffset, 0, 1, 0);
				} else {
					GlStateManager.rotate(90 - (player.prevRenderYawOffset + (player.renderYawOffset - player.prevRenderYawOffset) * partialTicks), 0, 1, 0);
				}
				GlStateManager.translate(player.isSneaking() ? 0.25D : 0.0D, (player.isSneaking() ? -0.15D : 0) - 0.2D, -0.25D);
				float limbSwingAmount = player.prevLimbSwingAmount + (player.limbSwingAmount - player.prevLimbSwingAmount) * partialTicks;
				float swing = (float)Math.sin((player.limbSwing - limbSwingAmount * (1.0F - partialTicks)) / 1.4F) * limbSwingAmount;
				GlStateManager.rotate(swing * 25.0F, 0, 0, 1);
				GlStateManager.rotate(swing * 13.0F, 1, 0, 0);
				GlStateManager.rotate(swing * -10.0F, 0, 0, 1);
				GlStateManager.translate(0, -0.1D, 0);
				GlStateManager.enableBlend();
				GlStateManager.color(1, 1, 1, 1);
				GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
				GlStateManager.pushMatrix();
				GlStateManager.translate(0, 0, 0.02D);
				GlStateManager.scale(0.4D, 0.4D, 0.5D);

				renderItem.renderItem(pouch, model);

				GlStateManager.popMatrix();

				GlStateManager.pushMatrix();
				GlStateManager.scale(0.37D, 0.37D, 0.5D);

				renderItem.renderItem(pouch, model);

				GlStateManager.popMatrix();

				GlStateManager.popMatrix();

				textureManager.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
				texture.restoreLastBlurMipmap();
			}
		}
	}

    @Override
    public EnumEquipmentInventory getEquipmentCategory(ItemStack stack) {
        return EnumEquipmentInventory.MISC;
    }

    @Override
    public boolean canEquipOnRightClick(ItemStack stack, EntityPlayer player, Entity target) {
        return false;
    }

    @Override
    public boolean canEquip(ItemStack stack, EntityPlayer player, Entity target) {
        return target == player && EquipmentHelper.getEquipment(EnumEquipmentInventory.MISC, target, this).isEmpty();
    }

    @Override
    public boolean canUnequip(ItemStack stack, EntityPlayer player, Entity target, IInventory inventory) {
        return true;
    }

    @Override
    public boolean canDrop(ItemStack stack, Entity entity, IInventory inventory) {
        return true;
    }

    @Override
    public void onEquip(ItemStack stack, Entity entity, IInventory inventory) {
    }

    @Override
    public void onUnequip(ItemStack stack, Entity entity, IInventory inventory) {
    }

    @Override
    public void onEquipmentTick(ItemStack stack, Entity entity, IInventory inventory) {
    }

	@Override
	@SideOnly(Side.CLIENT)
	public int getColorMultiplier(ItemStack stack, int tintIndex) {
		if (tintIndex == 1) {
			if (stack.getTagCompound() != null && stack.getTagCompound().hasKey("type")) {
				int type = stack.getTagCompound().getInteger("type");
				return EnumBLDyeColor.byMetadata(type).getColorValue();
			}
			else
				return EnumBLDyeColor.byMetadata(EnumBLDyeColor.CHAMPAGNE.getMetadata()).getColorValue(); // default to Pewter Grey
		}
		return  -1;
	}
}
