using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using Luski.GUI.MainScreen.Interfaces;
using Luski.GUI.MainScreen.UI.PublicServers;
using Luski.net.Structures.Public;
using Luski.Shared.PublicServers.V1.Enums;
using OpenTK.Graphics.OpenGL4;

namespace Luski.GUI.MainScreen.UI.Generic;

public class ChannelSelector : FlowLayout, IChannelAdder
{
    public SocketCategory CurrentCategory { get; private set; }
    private readonly List<Category> cc = new();
    private readonly List<Channel> LoadedChannels = new();
    public Dictionary<long, IChannelAdder> ChannelAdders = new();
    public Channel? Selected;
    
    public override void ResizeDraw(int x, int y, int sx, int sy, int sw, int sh)
    {
        if (OldHeight == Size.Y)
        {
            if (!UpdateScissorBox(ref x, ref y, ref sx, ref sy, ref sw, ref sh)) return;
            Window!.CopyFromFrontToBack(x, y, Size.X, Size.Y, x, y);
        }
        else if (OldHeight < Size.Y)
        {
            if (!UpdateScissorBox(ref x, ref y, ref sx, ref sy, ref sw, ref sh)) return;
            Window!.CopyFromFrontToBack(x, y, OldWidth, OldHeight, x, y);
            int nsh = sh - OldHeight+1;
            if (nsh <= 0) return;
            GL.Scissor(sx, Window!.CS.Y - sy - sh, sw, nsh);
            DrawBase();
            GL.Scissor(sx, Window!.CS.Y - sy - sh, sw, sh);
		    
            for (int i = 0; i < Controls.Length; i++)
            {
                if (!Controls[i].Loaded)
                {
                    BlockDraw = true;
                    Controls[i].LoadToParent(this, Window!);
                    BlockDraw = false;
                }
                if (Controls[i].Location.X >= Size.X ||
                    Controls[i].Location.Y >= Size.Y ||
                    Controls[i].Location.X + Controls[i].Size.X < OldWidth ||
                    Controls[i].Location.Y + Controls[i].Size.Y < OldHeight) continue;
						
						
                if (Controls[i] is IParent pp)
                {
                    pp.ResizeDraw(x,y,sx,sy,sw,sh);
                    GL.Scissor(sx, Window!.CS.Y - sy - sh, sw, sh);
                }
                else
                {
                    Controls[i].Draw(x,y,sx,sy,sw,sh);
                }
            }
        }
        else
        {
            if (!UpdateScissorBox(ref x, ref y, ref sx, ref sy, ref sw, ref sh)) return;
            Window!.CopyFromFrontToBack(x, y, Size.X, Size.Y, x, y);
        }
    }

    public async Task LoadSelectorRoot(SocketCategory Cat)
    {
        CurrentCategory = Cat;
        ChannelAdders.Add(Cat.ID, this);
        Cat.Server.MessageReceived += ServerOnMessageReceived;
        bool MakeChannels = await Cat.Server.User.HasAccessToCategory(Cat, ServerPermission.CreateChannels);
        bool MakeRoles = await Cat.Server.User.HasPermissions(ServerPermission.ManageRoles);
        if (MakeChannels || MakeRoles)
        {
            LuskiContextMenu lcm = new();
            if (MakeChannels)
            {
                Label l = lcm.AddLabel("Create Channel");
                l.Clicked += LOnClicked;
            }
            if (MakeRoles)
            {
                Label l = lcm.AddLabel("Create Role");
                l.Clicked += RLOnClicked;
            }
            ContextMenu = lcm;
        }
    }
    
    private async Task RLOnClicked(IRenderObject arg)
    {
        Globals.ms.Controls.Add(new AddChannel(this, CurrentCategory));
        TryDraw();
    }

    private async Task LOnClicked(IRenderObject arg)
    {
        Globals.ms.Controls.Add(new AddChannel(this, CurrentCategory));
        TryDraw();
    }

    private async Task ServerOnMessageReceived(SocketMessage arg)
    {
        if (Selected is null || arg.ChannelID != Selected.CurrentChannel.ID) return;
        bool u = Globals.ms.ChatBoxArea.MessageFlow.MaxScrollValue == Globals.ms.ChatBoxArea.MessageFlow.ScrollValue;
        await Globals.ms.ChatBoxArea.AddMessage(arg, u);
       
    }

    public async Task Load(SocketChannel currentchannel, List<SocketCategory> parents)
    {
        IChannelAdder b = this;
        SocketChannel[] chanspp = await b.CurrentCategory.GetChannels();
        foreach (SocketChannel v in chanspp)
        { 
            Channel f = await b.AddChannel(v);
            if (v.ID == currentchannel.ID)
            {
                await f.ToggleSelected();
            }
        }
        SocketCategory[] cats = await b.CurrentCategory.GetCategories();
        foreach (SocketCategory v in cats)
        {
            await b.AddCategory(v);
            Globals.ms.DrawFrame();
        }
        foreach (SocketCategory par in parents)
        {
            b.Extended = true;
            b = await b.AddCategory(par);
            Globals.ms.DrawFrame();
            chanspp = await par.GetChannels();
            foreach (SocketChannel v in chanspp)
            { 
                Channel f = await b.AddChannel(v);
                if (v.ID == currentchannel.ID)
                {
                    await f.ToggleSelected();
                }
            }
            cats = await par.GetCategories();
            foreach (SocketCategory v in cats)
            {
                await b.AddCategory(v);
                Globals.ms.DrawFrame();
            }
        }
        
    }
    
    public async Task<Channel> AddChannel(SocketChannel chan)
    {
        Channel[] tc = LoadedChannels.Where(s => s.CurrentChannel.ID == chan.ID).ToArray();
        if (tc.Length > 0)
        {
            Channel cat23 = tc[0];
            if (!Controls.Contains(cat23))
            {
                Controls.Add(cat23);
            }
                
            return cat23;
        }
        Channel cat2 = await Channel.MakeChannel(chan, this);
        LoadedChannels.Add(cat2);
        cat2.BackgroundColor = BackgroundColor;
        Controls.Add(cat2);
        return cat2;
    }

    public bool Extended { get; set; } = true;
    
    public async Task<Category> AddCategory(SocketCategory Cat, DateTime? dt = null)
    {
        Category[] tc = cc.Where(s => s.CurrentCategory.ID == Cat.ID).ToArray();
        if (tc.Length > 0)
        {
            Category cat23 = tc[0];
            if (!Controls.Contains(cat23))
            {
                Controls.Add(cat23);
            }
                
            return cat23;
        }
        Category cat = await Category.MakeCat(Cat, this);
        cc.Add(cat);
        cat.BackgroundColor = BackgroundColor;
        cat.tmp.BackgroundColor = BackgroundColor;
        cat.Members.BackgroundColor = BackgroundColor;
        Controls.Add(cat);
        return cat;
    }
}