using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using Luski.GUI.MainScreen.Interfaces;
using Luski.net.Structures.Public;
using OpenTK.Windowing.Common.Input;

namespace Luski.GUI.MainScreen.UI.PublicServers;

public class Category : UserControl, IChannelAdder
{
    public FlowLayout Members;
    public SocketCategory CurrentCategory { get; set; }
    private List<Category> cc = new();
    private List<Channel> cl = new();
    private Label ee;
    private ChannelSelector CS;

    public event Func<int, Task>? AddY; 
    
    private Label Name;
    public UserControl tmp;

    public static Task<Category> MakeCat(SocketCategory cat, ChannelSelector cs)
    {
        Category c = new();
        c.CurrentCategory = cat;
        c.CS = cs;
        c.Anchor = ObjectAnchor.All;
        c.Size = new(307.ScaleInt(), 40.ScaleInt());
        c.tmp = new()
        {
            Size = c.Size,
            Anchor = ObjectAnchor.Top | ObjectAnchor.Left,
            IgnoreHover = true
        };
        c.tmp.Clicked += c.TmpOnClicked;
        c.tmp.HoverMouse = MouseCursor.Hand;
        c.Controls.Add(c.tmp);
        c.tmp.Controls.Add(c.ee = new(Globals.DefaultFont)
        {
            Text = ">",
            Location = new(5.ScaleInt()),
            Color = cat.Color.ToColor4(),
            DIR = new(1,0),
            IgnoreHover = true
        });
        c.tmp.Controls.Add(c.Name = new Label(Globals.DefaultFont)
        {
            Text = cat.Name,
            Color = c.ee.Color,
            IgnoreHover = true
        });
        c.Clicked += c.AllOnClicked;
        c.Name.Location = new(26.ScaleInt(), (((c.Size.Y - c.Name.Size.Y)/2)), 0);
        c.Members = new()
        {
            Anchor = ObjectAnchor.All,
            Location = new(20.ScaleInt(), c.Size.Y, 0),
            IgnoreHover = true
        };
        c.ee.Location = new(c.ee.Location.X, c.Name.Location.Y, 0);
        c.Members.Size = new(c.Size.X - c.Members.Location.X, 0);
        c.Controls.Add(c.Members);
        c.Members.ForceDistanceUpdate(c);
        c.tmp.HoverMouse = MouseCursor.Hand;
        return Task.FromResult(c);
    }

    private Category()
    {
    }
    private async Task TmpOnClicked(IRenderObject arg)
    {
        BlockDraw = true;
        if (!Extended)
        {
            DateTime dt = DateTime.UtcNow;
            SocketChannel[] Channels = await CurrentCategory.GetChannels();
            Console.WriteLine(DateTime.UtcNow - dt);
            foreach (SocketChannel v in Channels)
            {
                Channel c = await AddChannel(v);
                c.LoadToParent(Members, Window!);
                _ = CatOnAddY(c.Size.Y);
            }
            Console.WriteLine(DateTime.UtcNow - dt);

            SocketCategory[] cats = await CurrentCategory.GetCategories();
            Console.WriteLine(DateTime.UtcNow - dt);
            foreach (SocketCategory v in cats)
            {
                var c = await AddCategory(v, dt);
                c.LoadToParent(Members, Window!);
                _ = CatOnAddY(c.Size.Y);
            }
            Console.WriteLine(DateTime.UtcNow - dt);
        }
        else
        {
            if (AddY is not null) await AddY.Invoke(-Members.Size.Y);
            this.Size = new(this.Size.X, this.Size.Y -Members.Size.Y);
            Members.Size = new(Members.Size.X, 0);
            //Members.Controls.Clear(false);
        }

        BlockDraw = false;

        Extended = !Extended;

       // Window!.ForceUpdate(new(Window.Size));
    }
    
    private bool e;
    public bool Extended
    {
        get => e;
        set
        {
            if (value)
            {
                ee.DIR = new(0,1);
                ee.Location = new(ee.Location.X, (ee.Location.Y - ee.Size.Y), 0);
            }
            else
            {
                ee.DIR = new(1,0);
                ee.Location = new(ee.Location.X, (ee.Location.Y + ee.Size.Y), 0);
            }
            e = value;
        }
    }

    private Task AllOnClicked(IRenderObject arg)
    {
        if (ClickCon is not null) _ = ClickCon.Invoke(this);
        return Task.CompletedTask;
    }
    
    public event Func<Category, Task>? ClickCon;
    
    public async Task<Category> AddCategory(SocketCategory Cat, DateTime? dt = null)
    {
        if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt);
        Category[] tc = cc.Where(s => s.CurrentCategory.ID == Cat.ID).ToArray();
        if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt);
        if (tc.Length > 0)
        {
            if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt);
            var cat2 = tc[0];
            if (!Members.Controls.Contains(cat2))
            {
                if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt);
                Members.Controls.Add(cat2);
                if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt);
                //Size = new(Size.X, Size.Y + cat2.Size.Y);
                _ = CatOnAddY(cat2.Size.Y);
                if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt);
                if (AddY is not null) _ = AddY.Invoke(cat2.Size.Y);
                if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt);
            }
                
            return cat2;
        }
        var cat = await Category.MakeCat(Cat, CS);
        cc.Add(cat);
        Members.Controls.Add(cat);
        cat.Size = new(this.Size.X, cat.Size.Y);
        cat.Members.BackgroundColor = BackgroundColor;
        cat.BackgroundColor = BackgroundColor;
        cat.tmp.BackgroundColor = BackgroundColor;
        Size = new(Size.X, Size.Y + cat.Size.Y);
        cat.AddY += CatOnAddY;
        if (AddY is not null) await AddY.Invoke(cat.Size.Y);
        return cat;
    }

    private async Task CatOnAddY(int arg)
    {
        this.Size = new(Size.X, Size.Y + arg);
    }

    public async Task<Channel> AddChannel(SocketChannel chan)
    {
        Channel[] tc = cl.Where(s => s.CurrentChannel.ID == chan.ID).ToArray();
        if (tc.Length > 0)
        {
            Channel cat2 = tc[0];
            if (!Members.Controls.Contains(cat2))
            {
                Members.Controls.Add(cat2);
                Size = new(Size.X, Size.Y + cat2.Size.Y);
                if (AddY is not null) _ = AddY.Invoke(cat2.Size.Y);
            }
                
            return cat2;
        }
        Channel cat = await Channel.MakeChannel(chan, CS);
        cl.Add(cat);
        cat.BackgroundColor = BackgroundColor;
        Size = new(Size.X, Size.Y + cat.Size.Y);
        Members.Controls.Add(cat);
        if (AddY is not null) await AddY.Invoke(cat.Size.Y);
        return cat;
    }
}