using System.Timers;
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Common.Input;
using OpenTK.Windowing.GraphicsLibraryFramework;
using Timer = System.Timers.Timer;

namespace Luski.GUI.MainScreen.UI.LuskiControls;

public class TextBox : UserControl
{
    private Label _watermark, _label;
    private bool use;
    private Rectangle Pointer;
    private Timer t;

    public int CursorLocation { get; set; } = 0;
    
    public TextBox()
    :base(Globals.ms.TextureManager.GetTextureResource("Textbox.png"))
    {
	    t = new(500);
	    t.Elapsed += TOnElapsed;
        TextureDisplay = TextureDisplay.Center;
        _label = new Label(Globals.DefaultFont)
        {
            HoverMouse = MouseCursor.IBeam,
            IgnoreHover = true
        };
        _watermark = new(_label.Font)
        {
	        Text = "Text Box",
            Color = new(128, 128, 128, 255),
            HoverMouse = MouseCursor.IBeam,
            IgnoreHover = true
        };
        Pointer = new()
        {
	        Size = new(1.ScaleInt(), 
		        (int)_label.LineHeight ),
	        Location = _watermark.Location,
	        BackgroundColor = Color4.White,
	        Visible = false
        };
        Controls.Add(Pointer);
	        
        Controls.Add(_label);
        Controls.Add(_watermark);
    }

    private void TOnElapsed(object? sender, ElapsedEventArgs e)
    {
	    Globals.ms.Invoke(new Action(() =>
	    {
		    Pointer.Visible = !Pointer.Visible;
	    }));
    }

    public event Func<KeyboardKeyEventArgs, Task>? KeyPress;
    
    public override void UnFocus()
    {
	    use = false;
	    t.Stop();
	    Pointer.Visible = false;
	    if (Window is not null && Window.focused == this)
		    Window.focused = null;
	    
    }
    public override void Focus()
    {
	    if (Window is not null)
	    {
		    if (Window.focused is not null)
		    {
			    Window.focused.UnFocus();
		    }
		    t.Start();

		    Window.focused = this;
		    use = true;
	    }
    }
    
    public override void LoadToParent(IParent parent, IWindow window)
    {
	    if (Loaded) return;
	    window.MouseDown += Window_MouseDown;
	    window.KeyDown += Window_KeyDown;
	    window.TextInput += WindowOnTextInput;
	    if (!window.Context.IsCurrent) window.Context.MakeCurrent();
	    base.LoadToParent(parent, window);
	    Pointer.Location = _watermark.Location;
    }
    
    private void WindowOnTextInput(TextInputEventArgs obj)
    {
	    if (!use) return;
	    Text = Text.Insert((int)CursorLocation, obj.AsString);
	    CursorLocation += obj.AsString.Length;
	    var f = _label.GetCharLocation((int)CursorLocation);
	    Pointer.Location = _label.Location + new Vector3i(f.X, f.Y, 0);
	    Pointer.Visible = true;
    }
    
    
    public char? PasswordChar { get => _label.PasswordChar; set => _label.PasswordChar = value; }

    private TextLocation tl = TextLocation.TopLeft;

    public TextLocation TextLocation
    {
	    get => tl;
	    set
	    {
		    tl = value;
		    if (!string.IsNullOrWhiteSpace(Text))
		    {
			    _label.Location = value switch
			    {
				    TextLocation.LineCenter =>  new(10.ScaleInt(),
					    ((Size.Y - _label.Size.Y) / 2), Location.Z),
				    _ => _label.Location
			    };
			    _watermark.Location = _label.Location;
		    }
		    else
		    {
			    _watermark.Location = value switch
			    {
				    TextLocation.LineCenter => new(10.ScaleInt(),
					    ((Size.Y - _watermark.Size.Y) / 2), Location.Z),
				    _ => _watermark.Location
			    };
			    _label.Location = _watermark.Location;
		    }
	    }
    } 
    
    public override bool Visible
    {
        get => base.Visible;
        set 
        {
            if (value == base.Visible) return;
            if (value)
            {
                if (!string.IsNullOrEmpty(_label.Text))
                {
                    _label.Visible = true;
                    _watermark.Visible = false;
                }
                else
                {
                    _label.Visible = false;
                    _watermark.Visible = true;
                }
            }
            else
            {
                _label.Visible = value;
                _watermark.Visible = value;
            }

            base.Visible = value;
        }
    }
    
    public FontInteraction Font { get => _label.Font; }
    public FontInteraction WatermarkFont { get => _watermark.Font; }
    
    public Color4 TextColor { get => _label.Color; set => _label.Color = value; }
    public Color4 WatermarkColor { get => _watermark.Color; set => _watermark.Color = value; }

    public bool AllowMultiLine { get; set; } = true;
    
    public string Text
	{
		get => _label.Text;
		set
		{
			int old = _label.Size.Y;
			_label.Text = value;
			if (!string.IsNullOrEmpty(value))
			{
				bool f = false;
				if (!_label.Visible)
				{
					f = true;
					_label.Visible = true;
					_label.Location = TextLocation switch
					{
						TextLocation.LineCenter => new(10.ScaleInt(), ((Size.Y - _label.Size.Y) / 2), Location.Z),
						_ => _label.Location
					};
					/*
					_label.Location = TextLocation switch
					{
						TextLocation.TrueCenterLeft => new(Location.X + 5, Location.Y + ((Size.Y - _label.TrueHeight) / 2) - (_label.Size.Y  - _label.TrueHeight), Location.Z),
						TextLocation.PostiveTureCenterLeft => new(Location.X + 5, Location.Y + ((Size.Y - _label.PostiveTrueHeight) / 2) - _label.Size.Y + _label.TrueHeight, Location.Z),
						TextLocation.PxLeft => new(Location.X + 5, Location.Y + ((Size.Y - _label.Size.Y) / 2), Location.Z),
						_ => new(Location.X + 5, Location.Y + 5, Location.Z)
					};*/
					_watermark.Location = _label.Location;
				}
				if (_watermark.Visible) _watermark.Visible = false;
				if (!f && TextLocation == TextLocation.LineCenter && old != _label.Size.Y)
				{
					//_label.Location = new(Location.X + 5, Location.Y + ((Size.Y - _label.TrueHeight) / 2) - (_label.Size.Y - _label.TrueHeight), Location.Z);
					_watermark.Location = _label.Location;
				}
			}
			else
			{
				if (_label.Visible) _label.Visible = false;
				if (!_watermark.Visible)
				{
					_watermark.Visible = true;
					_watermark.Location = TextLocation switch
					{
						TextLocation.LineCenter => new(10.ScaleInt(), ((Size.Y - _watermark.Size.Y) / 2), Location.Z),
						_ => _watermark.Location
					};
					/*
					_watermark.Location = TextLocation switch
					{
						TextLocation.TrueCenterLeft => new(Location.X + 5, Location.Y + ((Size.Y - _watermark.TrueHeight) / 2) - (_watermark.Size.Y  - _watermark.TrueHeight), Location.Z),
						TextLocation.PostiveTureCenterLeft => new(Location.X + 5, Location.Y + ((Size.Y - _label.PostiveTrueHeight) / 2) - _label.Size.Y + _label.TrueHeight, Location.Z),
						TextLocation.PxLeft => new(Location.X + 5, Location.Y + ((Size.Y - _watermark.Size.Y) / 2), Location.Z),
						_ => new(Location.X + 5, Location.Y + 5, Location.Z)
					};*/
					_label.Location = _label.Location;
				}
			}
		}
	}
    public string WatermarkText
    {
        get
        {
            return _watermark.Text;
        }
        set
        {
            _watermark.Text = value;
        }
    }

    public event Func<Task>? OnNewLine;
    public event Func<Task>? OnRemoveLine;
    
    private void Window_KeyDown(KeyboardKeyEventArgs obj)
    {
	    if (!use) return;
	    if (obj.Key == Keys.Left)
	    {
		    CursorLocation--;
		    var f = _label.GetCharLocation((int)CursorLocation);
		    Pointer.Location = _label.Location + new Vector3i(f.X, f.Y, 0);
		    Pointer.Visible = true;
	    }
	    if (obj.Key == Keys.Right)
	    {
		    if (CursorLocation != Text.Length)
		    {
			    CursorLocation++;
			    var f = _label.GetCharLocation((int)CursorLocation);
			    Pointer.Location = _label.Location + new Vector3i(f.X, f.Y, 0);
			    Pointer.Visible = true;
		    }
		    
	    }
	    if (obj.Key == Keys.CapsLock || obj.Key == Keys.Menu || obj.Key == Keys.LeftSuper || obj.Key == Keys.RightSuper || obj.Key == Keys.End || obj.Key == Keys.Home || obj.Key == Keys.PageDown || obj.Key == Keys.PageUp || obj.Key == Keys.Insert || obj.Key == Keys.Up || obj.Key == Keys.Down || obj.Key == Keys.Left || obj.Key == Keys.Right) return;
	    if (obj.Key == Keys.Backspace)
	    {
		    if (!(Text.Length > 0)) return;
		    if (Text[CursorLocation- 1] == '\n')
		    {
			    Size = new(Size.X, Size.Y - (int)_label.Font.PixelHeight);
			    if (OnRemoveLine is not null) OnRemoveLine.Invoke();
		    }
		    Text = Text.Remove(CursorLocation - 1, 1);
		    CursorLocation--;
		    var f = _label.GetCharLocation(CursorLocation);
		    Pointer.Location = _label.Location + new Vector3i(f.X, f.Y, 0);
		    Pointer.Visible = true;
	    }
	    if (obj.Key == Keys.Delete)
	    {
		    if (CursorLocation == Text.Length) return;
		    if (Text[CursorLocation] == '\n')
		    {
			    Size = new(Size.X, Size.Y - (int)_label.Font.PixelHeight);
			    if (OnRemoveLine is not null) OnRemoveLine.Invoke();
		    }
		    Text = Text.Remove(CursorLocation, 1);
	    }

	    if (obj.Key == Keys.Enter)
	    {
		    if (AllowMultiLine && obj.Shift)
		    {
			    BlockDraw = true;
			    Size = new(Size.X, Size.Y + (int)_label.Font.PixelHeight);
			    if (OnNewLine is not null) OnNewLine.Invoke().Wait();
			    BlockDraw = false;
			    Text += '\n';
		    }
		    else
		    {
			    
		    }
	    }

	    
	    
	    if (obj.Key == Keys.V && obj.Control && Window is not null) Text += Window.ClipboardString;
	    if (KeyPress is not null) _ = KeyPress.Invoke(obj);
    }

    private void Window_MouseDown(MouseButtonEventArgs e)
    {
	    if (MouseInside && e.Button == MouseButton.Button1)
	    {
		    use = true;
		    Focus();
	    }
	    else UnFocus();
    }
}