using System.ComponentModel;
using System.Reflection;
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.Classes;
using Luski.GUI.MainScreen.UI.LuskiControls;
using Luski.GUI.MainScreen.UI.SettingsPanel;
using OpenTK.Mathematics;

namespace Luski.GUI.MainScreen.UI;

public class SettingsMenu : UserControl
{
    private string BehindName;
    public FlowLayout page;
    public CategoryButton? Selected, apper;
    private FlowLayout fl;
    private Category? AppSettings;
    private FontInteraction f;
    private DropDown<ThemeDropButton> ThemeDrop;
    public SettingsMenu()
    {
        LuskiExperiments.Settings.Theme.EventToggled += ThemeOnEventToggled;
        BehindName = Globals.ms.Title;
        Globals.ms.Title = "Settings - Luski";
        base.BackgroundColor = new(34, 34, 34, 255);
        base.Size = Globals.ms.ClientSize;
        Anchor = ObjectAnchor.All;
        if (CategoryButton.seltec is null)
        {
            CategoryButton.seltec = Globals.ms.TextureManager.GetTextureResource("RoundedRectangle.png");
        }
        fl = new()
        {
            BackgroundColor = new(20, 20, 20, 255),
            Size = new(307.ScaleInt(), base.Size.Y),
            Anchor = ObjectAnchor.Top | ObjectAnchor.Left | ObjectAnchor.Bottom
        };
        f = Globals.DefaultFont.Clone();
        f.FontSize = FontSize.Bold;
        f.PixelHeight = (uint)(f.PixelHeight * 1.4f);
        AppSettings = new("APP SETTINGS");
        CategoryButton cb3 = new("General", this)
        {
            OnPageLoad = () =>
            {
                page!.Controls.Add(new Label(f)
                {
                    Text = " \nGeneral\n "
                });
                foreach (PropertyInfo prop in typeof(Settings).GetProperties())
                {
                    object PropVal = prop.GetValue(Globals.Settings)!;
                    Type PropType = prop.PropertyType;
                    if (PropType.IsEnum)
                    {
                        IEnumerable<Enum> values = Enum.GetValues(PropType).Cast<Enum>();
                        foreach (var val in values)
                        {
                            try
                            {
                                MemberInfo[] memberInfos = 
                                    PropType.GetMember(val.ToString());
                                MemberInfo? enumValueMemberInfo = memberInfos.FirstOrDefault(m => 
                                    m.DeclaringType == PropType);
                                object[] valueAttributes = 
                                    enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
                                if (valueAttributes.Length == 0) continue;
                                string description = ((DescriptionAttribute)valueAttributes[0]).Description;
                    
                                AddBool(description, ((Enum)PropVal).HasFlag(val), bb =>
                                {
                                    long va = Convert.ToInt64(val);
                                    long v = Convert.ToInt64(PropVal);
                                    if (bb)
                                    {
                                        object e = Enum.Parse(PropType, (v + va).ToString());
                                        PropVal = e;
                                        prop.SetValue(Globals.Settings, e);
                                    }
                                    else
                                    {
                                        var e = Enum.Parse(PropType, (v - va).ToString());
                                        PropVal = e;
                                        prop.SetValue(Globals.Settings, e);
                                    }
                                    Globals.Settings.SaveSettings(Path.Combine(Globals.LuskiPath, "Settings.json"), SettingsContext.Default.Settings);
                                });
                            }
                            catch
                            {
                                //ignore
                            }
                        }
                    }
                    if (PropType.FullName == typeof(bool).FullName)
                    {
                        try
                        {
                            object[] valueAttributes = 
                                prop.GetCustomAttributes(typeof(DescriptionAttribute), false);
                            string description = ((DescriptionAttribute)valueAttributes[0]).Description;
                            AddBool(description, (bool)PropVal, b =>
                            {
                                prop.SetValue(Globals.Settings, b);
                                Globals.Settings.SaveSettings(Path.Combine(Globals.LuskiPath, "Settings.json"), SettingsContext.Default.Settings);
                            });
                        }
                        catch
                        {
                            // ignored
                        }

                        
                    }
                }
            }
        };
        AppSettings.AddButton(cb3);
        
        fl.Controls.Add(AppSettings);

        if (LuskiExperiments.Settings.Theme.IsEnabled())
        {
            Label Top = new(Globals.DefaultFont)
            {
                Location = new(5.ScaleInt(), 5.ScaleInt(), 0),
                Text = LuskiThemes.Dark.Name
            };
            CategoryButton cb2 = new("Appearance", this)
            {
                OnPageLoad = () =>
                {
                    page!.Controls.Add(new Label(f)
                    {
                        Text = " \nAppearance\n "
                    });
                    ThemeDropButton LightDD;
                    ThemeDrop = new(CategoryButton.seltec!,new Rectangle()
                    {
                        Size = new(base.Size.X - 2, 1.ScaleInt()),
                        BackgroundColor = Color4.Gray,
                        Location = new(1, base.Size.Y - 1.ScaleInt(), 0),
                        Anchor = ObjectAnchor.Left | ObjectAnchor.Right | ObjectAnchor.Bottom
                    }, LightDD = new(LuskiThemes.Light)
                    {
                        LoadDisplay = () =>
                        {
                            Label ll = new Label(Globals.DefaultFont)
                            {
                                Text = LuskiThemes.Light.Name,
                                Color = Color4.DarkGray,
                                IgnoreHover = true
                            };
                            ll.Location = new(10.ScaleInt(),
                                ((ThemeDrop.Size.Y - ll.Size.Y) / 2)
                                , 0);
                            ThemeDrop.Controls.Add(ll);
                        },
                        Size = new(297.ScaleInt(), 40.ScaleInt()),
                    }){DropDownParentOverride = Globals.ms,Size = new(40.ScaleInt()),
                        Location = new(Top.Location.X, Top.Location.Y, 0),
                        BackgroundColor = new(40, 40, 40, 255),
                        Anchor = ObjectAnchor.Right | ObjectAnchor.Left,};
                    foreach (ThemeStart themeStart in LuskiThemes.LuskiThemeList)
                    {
                        if (themeStart.Name == LuskiThemes.Light.Name) continue;
                        ThemeDropButton tdb;
                        ThemeDrop.AddOption(tdb = new(themeStart)
                        {
                            LoadDisplay = () =>
                            {
                                Label ll = new Label(Globals.DefaultFont)
                                {
                                    Text = themeStart.Name,
                                    Color = Color4.DarkGray,
                                    IgnoreHover = true
                                };
                                ll.Location = new(10.ScaleInt(),
                                    ((ThemeDrop.Size.Y - ll.Size.Y) / 2)
                                    , 0);
                                ThemeDrop.Controls.Add(ll);
                            },
                            Size = new(297.ScaleInt(), 40.ScaleInt()),
                        });
                        if (themeStart.Name == Globals.Settings.Theme) ThemeDrop.SetSelected(tdb);
                    }
                    ThemeDrop.DropDownContainer.Textures.Add(Globals.ms.TextureManager.GetTextureResource("RoundedRectangleBottom.png"));
                    ThemeDrop.DropDownContainer.TextureDisplay = TextureDisplay.Center;
                    ThemeDrop.DropDownContainer.Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context];
                    ThemeDrop.DropDownContainer.BackgroundColor = ThemeDrop.BackgroundColor;
                    Rectangle line = new()
                    {
                        Size = new(base.Size.X - 2, 1.ScaleInt()),
                        BackgroundColor = Color4.Gray,
                        Location = new(1, base.Size.Y - 1.ScaleInt(), 0),
                        Anchor = ObjectAnchor.Left | ObjectAnchor.Right | ObjectAnchor.Bottom
                    };
                    ThemeDrop.OpenStatusChanged += b =>
                    {
                        BlockDraw = true;
                        Size = new(base.Size.X, base.Size.Y + ( b ? ThemeDrop.DropDownContainer.Size.Y : -1 * ThemeDrop.DropDownContainer.Size.Y));
                        line!.Location = new(line.Location.X,
                            line.Location.Y + (b ? ThemeDrop.DropDownContainer.Size.Y : -1 * ThemeDrop.DropDownContainer.Size.Y), 0);
                        if (b)
                        {
                            ThemeDrop.Textures[0] = Globals.ms.TextureManager.GetTextureResource("RoundedRectangleTop.png");
                        }
                        else
                        {
                            ThemeDrop.Textures[0] = CategoryButton.seltec!;
                        }

                        BlockDraw = false;
                        return Task.CompletedTask;
                    };
                    page!.Controls.Add(ThemeDrop);
                }
            };
            AppSettings.AddButton(cb2);
            fl.Controls.Insert(0, AppSettings);
            fl.ScrollToBottom();
        }
        page = new()
        {
            BackgroundColor = this.BackgroundColor,
            Location = new(fl.Size.X + 40.ScaleInt(), 0, 0),
            Size = new(Globals.ms.ClientSize.X - fl.Size.X - 80.ScaleInt(), Globals.ms.Size.Y),
            AllowHoverFromBehind = true,
            Anchor = ObjectAnchor.All,
            HScrollPixels = Globals.Settings.PerScrollPixels
        };
        Controls.Add(page);
        void AddBool(string Name, bool s, Action<bool> a)
        {
            ToggleSwitch ts = new()
            {
                Value = s
            };
            UserControl tc = new()
            {
                Size = ts.Size,
                BackgroundColor = page.BackgroundColor
            };
            Label l;
            tc.Controls.Add(l =new Label(Globals.DefaultFont)
            {
                Text = Name + ": "
            });
            tc.Size = l.Size;
            tc.Controls.Add(ts);
            ts.Location = new(l.Size.X + 10.ScaleInt(), 0, 0);

                    
            ts.ValueChanged += @switch =>
            {
                a.Invoke(@switch .Value);
                return Task.CompletedTask;
            };
            page.Controls.Add(tc);
        }
        page.ForceDistanceUpdate(this);
        Category As = new("ADVANCED SETTINGS");
        CategoryButton cb = new("Experiments", this)
        {
            OnPageLoad = () =>
            {
                page!.Controls.Add(new Label(f)
                {
                    Text = " \nExperiments\n "
                });
                ExperimentGUI? g = null;
                foreach (ExperimentInfo exp in Globals.Experiments)
                {
                    g = new(exp);
                    page.Controls.Add(g);
                }

                if (g is not null)
                {
                    g.line.WindowLoaded += _ =>
                    {
                        page.ParentResize(new(Globals.ms.ClientSize));
                        return Task.CompletedTask;
                    };
                }
            }
        };
        CategoryButton us = new("Updater Config", this)
        {
            OnPageLoad = () =>
            {
                page!.Controls.Add(new Label(f)
                {
                    Text = " \nUpdater Config\n "
                    
                });

                TextBox t;
                page!.Controls.Add(t =new TextBox()
                {
                    Text = Globals.UpdaterSettings.Updater!,
                    WatermarkText = "Updater File",
                    TextureDisplay = TextureDisplay.Center,
                    Size = new(page.Size.X, 34.ScaleInt()),
                    TextLocation = TextLocation.LineCenter,
                    AllowMultiLine = false
                });
                foreach (PropertyInfo prop in typeof(UpdaterSettings).GetProperties())
                {
                    object PropVal = prop.GetValue(Globals.UpdaterSettings)!;
                    Type PropType = prop.PropertyType;
                    if (PropType.IsEnum)
                    {
                        IEnumerable<Enum> values = Enum.GetValues(PropType).Cast<Enum>();
                        foreach (var val in values)
                        {
                            try
                            {
                                MemberInfo[] memberInfos = 
                                    PropType.GetMember(val.ToString());
                                MemberInfo? enumValueMemberInfo = memberInfos.FirstOrDefault(m => 
                                    m.DeclaringType == PropType);
                                object[] valueAttributes = 
                                    enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
                                if (valueAttributes.Length == 0) continue;
                                string description = ((DescriptionAttribute)valueAttributes[0]).Description;
                    
                                AddBool(description, ((Enum)PropVal).HasFlag(val), bb =>
                                {
                                    long va = Convert.ToInt64(val);
                                    long v = Convert.ToInt64(PropVal);
                                    if (bb)
                                    {
                                        object e = Enum.Parse(PropType, (v + va).ToString());
                                        PropVal = e;
                                        prop.SetValue(Globals.Settings, e);
                                    }
                                    else
                                    {
                                        var e = Enum.Parse(PropType, (v - va).ToString());
                                        PropVal = e;
                                        prop.SetValue(Globals.UpdaterSettings, e);
                                    }
                                    Globals.UpdaterSettings.SaveSettings(Path.Combine(Globals.LuskiPath, "UpdaterSettings.json"), UpdaterSettingsContext.Default.UpdaterSettings);
                                });
                            }
                            catch
                            {
                                //ignore
                            }
                        }
                    }
                    if (PropType.FullName == typeof(bool).FullName)
                    {
                        try
                        {
                            object[] valueAttributes = 
                                prop.GetCustomAttributes(typeof(DescriptionAttribute), false);
                            string description = ((DescriptionAttribute)valueAttributes[0]).Description;
                            AddBool(description, (bool)PropVal, b =>
                            {
                                prop.SetValue(Globals.UpdaterSettings, b);
                                Globals.UpdaterSettings.SaveSettings(Path.Combine(Globals.LuskiPath, "UpdaterSettings.json"), UpdaterSettingsContext.Default.UpdaterSettings);
                            });
                        }
                        catch
                        {
                            // ignored
                        }
                    }
                    
                }
                
                t.ForceDistanceUpdate(page);
                t.KeyPress += args =>
                {
                    Globals.UpdaterSettings.Updater = t.Text;
                    Globals.UpdaterSettings.SaveSettings(Path.Combine(Globals.LuskiPath, "UpdaterSettings.json"), UpdaterSettingsContext.Default.UpdaterSettings);
                    return Task.CompletedTask;
                };
                TryDraw();
                Globals.ms.ForceUpdate(new(Globals.ms.CS));
            }
        };
        As.AddButton(cb);
        As.AddButton(us);
        fl.Controls.Add(As);
        
       
        fl.ForceDistanceUpdate(this);
        _ = cb3.ToggleSelected();
        
        Rectangle closebtn = new(Globals.ms.TextureManager.GetTextureResource("close.png"))
        {
            Location = new(Globals.ms.ClientSize.X - 40.ScaleInt(), 8.ScaleInt(),0),
            Size = new(32.ScaleInt()),
            Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
            BackgroundColor = Color4.Gray,
            Anchor = ObjectAnchor.Top | ObjectAnchor.Right
        };
        closebtn.MouseEnter += _ =>
        {
            closebtn.BackgroundColor = Color4.White;
            return Task.CompletedTask;
        };
        closebtn.MouseLeave += _ =>
        {
            closebtn.BackgroundColor = Color4.Gray;
            return Task.CompletedTask;
        };
        closebtn.Clicked += ClosebtnOnClicked;
        closebtn.ForceDistanceUpdate(this);
        Controls.Add(closebtn);
        Controls.Add(fl);
    }

    private Task ThemeOnEventToggled(bool arg)
    {
        if (arg)
        {
            apper = new("Appearance", this)
            {
                OnPageLoad = () =>
                {
                    page.Controls.Add(new Label(f)
                    {
                        Text = " \nAppearance\n "
                    });
                }
            };
            AppSettings!.AddButton(apper);
            fl.ScrollToBottom();
        }
        else
        {
            AppSettings!.RemoveButton(apper);
        }

        return Task.CompletedTask;
    }

    private Task ClosebtnOnClicked(IRenderObject arg)
    {
        Globals.ms.Controls.Remove(this);
        Globals.ms.Title = BehindName;
        Globals.ms.DrawFrame();
        return Task.CompletedTask;
    }
}