using GraphicsManager.Interfaces;
using GraphicsManager.Objects.Core;
using GraphicsManager.Structs;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;

namespace Luski.GUI.MainScreen.UI.LuskiControls;

public class AdvancedGradientLabel : LabelBase
{
    public AdvancedGradientLabel(FontInteraction fi) : base(fi) { }

    public Color4[] Colors { get; set; } = new[]
    {
	    new Color4(255, 255, 255, 255),
	    new Color4(255, 255, 255, 255)
    };

    protected virtual (Color4,Color4) getcols(int charter)
	{
	    Vector2i cl = GetCharLocation(charter);
	    Vector2i cs = GetSizeOfChar(charter);
	    return new(getcol(cl.X), getcol(cl.X + cs.X));
	}
	protected virtual Color4 getcol(int pos)
	{
	    float travel =  (float)Size.X/(Colors.Length - 1);
	    int i = 1;
	    while (travel * i < pos)
	    {
		    i++;
	    }
	    i--;
	    float t = Math.Clamp((pos-(travel*i))/travel, 0, 1);
	    Color4 LeftColor = Colors[i], RightColor = Colors[i + 1];

	    float r = LeftColor.R + (RightColor.R - LeftColor.R) * t;
	    float g = LeftColor.G + (RightColor.G - LeftColor.G) * t;
	    float b = LeftColor.B + (RightColor.B - LeftColor.B) * t;
	    float a = LeftColor.A + (RightColor.A - LeftColor.A) * t;

	    return new Color4(r, g, b, a);
	}
    public override void LoadToParent(IParent window, IWindow win)
    {
	    if (Loaded) return;
	    if (Shader is null) Shader = Globals.GradientShader[win.Context];
	    base.LoadToParent(window, win);
    }

    public override void Draw(int x, int y, int sx, int sy, int sw, int sh)
    {
	    if (Visible && Loaded && this.Font is not null && Colors.Length > 1)
		{
			if (!Window!.Context.IsCurrent) Window.Context.MakeCurrent();
			Shader.Use();
			GL.Enable(EnableCap.Blend);
			GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
			GL.BlendFunc(0, BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
			Shader.SetMatrixF4("projection", Window.WindowSizeMatrix);

			GL.BindVertexArray(VAO);

			float angle_rad = (float)Math.Atan2(DIR.Y, DIR.X);
			Matrix4 rotateM = Matrix4.CreateRotationZ(angle_rad);
			Matrix4 transOriginM = Matrix4.CreateTranslation(new Vector3(loc_.X + Parent!.IntToWindow(0), loc_.Y + (Font.PixelHeight * Scale) + Parent!.IntToWindow(0, true), 0f));
			 float char_x = 0.0f;
			 Matrix4 staticTransform = rotateM * transOriginM;
			 GL.UniformMatrix4(0, false, ref staticTransform);
			
			GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
			GL.ActiveTexture((Shader.GetUniformLocation("u_texture") switch
			{
				0 => TextureUnit.Texture0,
				1 => TextureUnit.Texture1,
				2 => TextureUnit.Texture2,
				3 => TextureUnit.Texture3,
				4 => TextureUnit.Texture4,
				5 => TextureUnit.Texture5,
				6 => TextureUnit.Texture6,
				7 => TextureUnit.Texture7,
				8 => TextureUnit.Texture8,
				9 => TextureUnit.Texture9,
			}));
			
			float hhh = 0f;
			for (int i = 0; i < text_Calculated.Length; i++)
			{
				var col = getcols(i);
				GL.Uniform4(Shader.GetUniformLocation("textColor"), col.Item1);
				GL.Uniform4(Shader.GetUniformLocation("rightColor"), col.Item2);
				char c;
				if (PasswordChar is null)
					c = text_Calculated[i];
				else
					c = PasswordChar.Value;
				bool n = (c == '\n');
				if (!_characters[Window!.Context][Font].ContainsKey(c) && !n)
				{
					_ = Texture.TextureForChar(Window!.Context, Font, c, Shader);
				}
				
                if (n)
                {
                	hhh += LineHeight;
	                hhh += Font.ExtraLinePixels;
                	char_x = 0f;
                }
                else
                {
	                if (!_characters[Window!.Context][Font].ContainsKey(c)) continue;
	                Character ch = _characters[Window!.Context][Font][c];
					
                	float w = ch.Size.X * Scale;
                	float h = ch.Size.Y * Scale;
                	float xrel = char_x + ch.Bearing.X * Scale;
                	float yrel = (ch.Size.Y - ch.Bearing.Y) * Scale;
                	yrel += hhh;
                	char_x += (ch.Advance >> 6) * Scale;
	                
	                GL.Uniform2(Shader.GetUniformLocation("scale"), w, h);
	                GL.Uniform2(Shader.GetUniformLocation("offset"), xrel, yrel);
	                
                	ch.Texture.Use();

                	GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
                }
			}
        }
    }
}