package projectzombie.menu.gui;

import org.lwjgl.opengl.GL33;

import gl_engine.MathHelpers;
import gl_engine.matrix.Matrix4;
import gl_engine.vec.Vec2d;
import gl_engine.vec.Vec3d;
import projectzombie.Main;
import projectzombie.entity.EntityItem;
import projectzombie.init.Models;
import projectzombie.model.Model;
import projectzombie.text.Text;
import projectzombie.util.ItemStack;
import projectzombie.world.layer.Layer;

public class GUIItemHolder implements GUIComponent
{
	private GUIItemSlot hover = null;
	private ItemStack holding = ItemStack.getEmpty();
	private GUIContainer gui;
	
	public GUIItemHolder(GUIContainer gui) {
		this.gui = gui;
	}

	@Override
	public void render(Matrix4 matrix, Vec2d mousePos, boolean canHover)
	{
		matrix = Matrix4.translate(mousePos.x, mousePos.y, 0);
		
		if(!holding.isEmpty())
		{
			Matrix4 holding_matrix = Matrix4.multiply(matrix, Matrix4.translate(-0.425, -0.425, 0));
			
			Model model = holding.item.getModel(holding).getGuiModel();
			
			model.setModel(holding_matrix);
			model.render();
			
			double damage = holding.item.getDamage(holding);
			
			if(damage > 0)
			{
				Matrix4 matrix_damage = Matrix4.multiply(holding_matrix, Matrix4.translate(0, -0.85 / 16, 0));
				matrix_damage = Matrix4.multiply(Matrix4.scale(new Vec3d(damage * 0.85, 0.85 / 16, 0)), matrix_damage);
				
				GL33.glUniform4f(Main.window.glsl_color,
						1 - (float)MathHelpers.squared(1 - damage),
						1 - (float)MathHelpers.squared(damage), 0, 1);
				
				Models.UI_PIXEL_WHITE.setModel(matrix_damage);
				Models.UI_PIXEL_WHITE.render();
				
				GL33.glUniform4f(Main.window.glsl_color, 1, 1, 1, 1);
			}
			
			if(holding.count > 1)
			{
				Matrix4 text_matrix = Matrix4.multiply(holding_matrix, Matrix4.translate(-0.75 / 4, -0.75 / 4, 0));
				text_matrix = Matrix4.multiply(Matrix4.scale(new Vec3d(0.4, 0.4, 0.4)), text_matrix);
				
				Text.render("" + holding.count, text_matrix);
			}
		}
		
		if(hover != null && holding.isEmpty())
		{
			ItemStack stack = hover.getItemStack();
			
			if(!stack.isEmpty())
			{
				String name = stack.item.getName(stack);
				
				Matrix4 container_matrix = matrix;
				double distance = 0.5;
				double offset = -0.6 - distance;
				
				if(Matrix4.multiply(matrix, new Vec3d(0, offset - 0.8, 0)).y < -10) {
					offset = 0.2 + distance;
				}
				
				container_matrix = Matrix4.multiply(container_matrix, Matrix4.translate(
						-0.4 * name.length() / 2, offset, 0));
				
				Matrix4 text_matrix = container_matrix;
				
				text_matrix = Matrix4.multiply(Matrix4.scale(new Vec3d(0.4, 0.4, 0.4)), text_matrix);
				container_matrix = Matrix4.multiply(container_matrix, Matrix4.translate(-0.2, -0.2, 0));
				container_matrix = Matrix4.multiply(Matrix4.scale(new Vec3d(
						(0.4 * (name.length() + 1)), 0.8, 0)), container_matrix);
				
				Models.UI_TEXT_BG.setModel(container_matrix);
				Models.UI_TEXT_BG.render();
				
				Text.render(name, text_matrix);
			}
		}
	}

	@Override
	public void update(Vec2d mousePos) {
		hover = gui.getHoveringItemSlot(mousePos);
	}

	@Override
	public boolean checkMouseHover(Vec2d pos) {
		return true;
	}
	
	private void hoverToStack(Vec2d pos)
	{
		ItemStack hover = this.hover.getItemStack();
		
		if(!holding.isEmpty() && (!holding.stackEquals(hover) || holding.count + hover.count > holding.item.max)) {
			return;
		}
		
		holding.count += hover.count;
		holding.modifiers = hover.copyModifiers();
		holding.item = hover.item;
		
		hover.count = 0;
		
		this.hover.setItemStack(hover);
		this.hover.getter.onRemoveItemStack();
	}
	
	@Override
	public void onRightClick(Vec2d pos)
	{
		// Drop part of the holding item if the hover item doesn't exist
		if(hover == null || this.hover.getter.isReadOnly())
		{
			if(!holding.isEmpty())
			{
				Layer layer = Main.world.getLayer();
				
				layer.spawnEntity(new EntityItem(
						Main.player.getPos(), Main.player.getVelocity(),
						new ItemStack(holding.item, 1, holding.copyModifiers()),
						Math.toRadians(Main.player.angle)));
				
				holding.count -= 1;
			}
			
			return;
		}
		
		if(hover.getter.mustTakeAll()) {
			hoverToStack(pos);
			return;
		}
		
		ItemStack hover = this.hover.getItemStack();
		
		// Split the hovered slot in half if the holding slot is empty
		if(holding.isEmpty())
		{
			holding.item = hover.item;
			holding.modifiers = hover.copyModifiers();
			
			holding.count = (int)Math.ceil(hover.count / 2.0);
			hover.count = (int)Math.floor(hover.count / 2.0);
			
			this.hover.setItemStack(hover);
			this.hover.getter.onRemoveItemStack();
		}
		
		// Put 1 item into the slot if the hovered slot is empty or equal to the holding slot
		else
		{
			ItemStack stack_from = hover;
			ItemStack stack_to = holding;
			
			if(!this.hover.isItemAllowed(stack_to)) {
				stack_from = holding;
				stack_to = hover;
			}
			
			if(
					stack_from.count + 1 <= stack_from.item.max && stack_to.count - 1 <= stack_to.item.max &&
					(stack_from.isEmpty() || stack_from.stackEquals(stack_to))
			) {
				stack_from.count += 1;
				stack_to.count -= 1;
				
				stack_from.item = stack_to.item;
				stack_from.modifiers = stack_to.copyModifiers();
				
				this.hover.setItemStack(hover);
				this.hover.getter.onRemoveItemStack();
			}
		}
	}

	@Override
	public void onMouseClick(Vec2d pos)
	{
		// Drop the holding item if the hover item doesn't exist
		if(hover == null || this.hover.getter.isReadOnly())
		{
			if(!holding.isEmpty())
			{
				Layer layer = Main.world.getLayer();
				
				layer.spawnEntity(new EntityItem(
						Main.player.getPos(), Main.player.getVelocity(),
						holding.copy(), Math.toRadians(Main.player.angle)));
				
				holding.count = 0;
			}
			
			return;
		}
		
		if(hover.getter.mustTakeAll()) {
			hoverToStack(pos);
			return;
		}
		
		ItemStack hover = this.hover.getItemStack();
		
		// Are these the same item
		if(holding.stackEquals(hover) && !holding.isEmpty() && !hover.isEmpty())
		{
			ItemStack stack_from = hover;
			ItemStack stack_to = holding;
			
			if(!this.hover.isItemAllowed(stack_to)) {
				stack_from = holding;
				stack_to = hover;
			}
			
			// Merge the hover stack into the holding stack
			if(stack_to.count + stack_from.count > stack_to.item.max) {
				int overflow = stack_to.count + stack_from.count - stack_to.item.max;
				stack_from.count = stack_to.item.max;
				stack_to.count = overflow;
			}
			
			else {
				stack_from.count += stack_to.count;
				stack_to.count = 0;
			}
			
			this.hover.setItemStack(hover);
			this.hover.getter.onRemoveItemStack();
		}
		
		else if(holding.isEmpty() || this.hover.isItemAllowed(holding))
		{
			// Swap the stacks
			ItemStack stack = holding.copy();
			
			holding.count = hover.count;
			holding.item = hover.item;
			holding.modifiers = hover.copyModifiers();
			
			hover.count = stack.count;
			hover.item = stack.item;
			hover.modifiers = stack.copyModifiers();
			
			this.hover.setItemStack(hover);
			this.hover.getter.onRemoveItemStack();
		}
	}

	@Override
	public void onActivate() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onBack()
	{
		if(!holding.isEmpty())
		{
			Layer layer = Main.world.getLayer();
			
			layer.spawnEntity(new EntityItem(
					Main.player.getPos(), Main.player.getVelocity(),
					holding.copy(), Math.toRadians(Main.player.angle)));
			
			holding.count = 0;
		}
	}
	
	@Override
	public void onScroll(Vec2d mousePos, double amount) {
	}

}
