using System;
using System.Collections.Generic;
using System.Numerics;
using Robust.Client.AutoGenerated;
using Robust.Client.Console.Commands;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Maths;

namespace Robust.Client.UserInterface;

[GenerateTypedNameReferences]
public sealed partial class DevWindowTabUI : Control
{
    [Dependency] private readonly IClydeInternal _clyde = default!;
    [Dependency] private readonly IInputManager _input = default!;

    public Control? SelectedControl { get; private set; }
    private Dictionary<Control, DevWindowUITreeEntry> ControlMap { get; } = new();
    private Control? LastHoveredControl { get; set; }

    public event Action? SelectedControlChanged;

    public DevWindowTabUI()
    {
        InitializeComponent();

        TopbarButtons.PanelOverride = new StyleBoxFlat
        {
            BorderThickness = new Thickness(0, 0, 0, 1),
            BorderColor = Color.Gray,
            ContentMarginLeftOverride = 3,
            ContentMarginRightOverride = 3,
            ContentMarginBottomOverride = 1,
            ContentMarginTopOverride = 3,
        };
        TreeRootBG.PanelOverride = new StyleBoxFlat
        {
            BorderThickness = new Thickness(0, 0, 1, 0),
            BorderColor = Color.Gray,
            ContentMarginLeftOverride = 3,
            ContentMarginBottomOverride = 3,
        };
    }

    private void InitializeComponent()
    {
        RobustXamlLoader.Load(this);
        IoCManager.InjectDependencies(this);

        ControlTreeRoot.OnKeyBindDown += ControlTreeRootOnKeyBindDown;
        RefreshPropertiesButton.OnPressed += _ => Refresh();
    }

    private Control? GetControlUnderMouse()
    {
        return UserInterfaceManager.MouseGetControl(_input.MouseScreenPosition);
    }

    private void OnMouseMove(MouseMoveEventArgs obj)
    {
        if (!ControlPicker.Pressed)
            return;

        var controlUnderMouse = GetControlUnderMouse();
        if (LastHoveredControl == controlUnderMouse)
            return;

        LastHoveredControl = controlUnderMouse;

        Stack<Control> entryStack = new();
        DevWindowUITreeEntry? entry = null;
        var control = controlUnderMouse;
        while (control != null)
        {
            if (ControlMap.TryGetValue(control, out entry))
                break;

            entryStack.Push(control);
            control = control.Parent;
        }

        if (entry == null)
            return;

        if (entryStack.Count > 0)
            entry.Open();

        foreach (var subEntry in entryStack)
        {
            ControlMap[subEntry].Open();
        }

        SelectControl(controlUnderMouse);
    }

    private bool OnUIKeyBindStateChanged(BoundKeyEventArgs arg)
    {
        if (arg.Function != EngineKeyFunctions.UIClick)
            return false;

        if (!ControlPicker.Pressed)
            return false;

        var control = GetControlUnderMouse();
        if (control == ControlPicker)
            return false;

        ControlPicker.Pressed = false;
        return true;
    }

    private void ControlTreeRootOnKeyBindDown(GUIBoundKeyEventArgs obj)
    {
        if (obj.Function != EngineKeyFunctions.UIClick)
            return;

        obj.Handle();
        SelectControl(null);
    }

    protected override void EnteredTree()
    {
        base.EnteredTree();

        // Load tree roots.
        foreach (var root in UserInterfaceManager.AllRoots)
        {
            var entry = new DevWindowUITreeEntry(this, root);

            ControlTreeRoot.AddChild(entry);
        }

        UserInterfaceManager.OnPostDrawUIRoot += OnPostDrawUIRoot;
        _clyde.MouseMove += OnMouseMove;
        _input.UIKeyBindStateChanged += OnUIKeyBindStateChanged;
    }

    protected override void ExitedTree()
    {
        base.ExitedTree();

        // Clear tree children.
        ControlTreeRoot.RemoveAllChildren();

        UserInterfaceManager.OnPostDrawUIRoot -= OnPostDrawUIRoot;
        _clyde.MouseMove -= OnMouseMove;
        _input.UIKeyBindStateChanged -= OnUIKeyBindStateChanged;
    }

    private void OnPostDrawUIRoot(PostDrawUIRootEventArgs eventArgs)
    {
        if (SelectedControl == null || eventArgs.Root != SelectedControl.Root)
            return;

        var rect = UIBox2i.FromDimensions(SelectedControl.GlobalPixelPosition, SelectedControl.PixelSize);
        eventArgs.DrawingHandle.DrawRect(rect, Color.Cyan.WithAlpha(0.35f));
    }

    internal void EntryAdded(DevWindowUITreeEntry entry)
    {
        ControlMap[entry.VisControl] = entry;
    }

    public void EntryRemoved(DevWindowUITreeEntry entry)
    {
        if (SelectedControl == entry.VisControl)
            SelectControl(null);

        ControlMap.Remove(entry.VisControl);
    }

    public void SelectControl(Control? control)
    {
        SelectedControl = control;

        SelectedControlChanged?.Invoke();

        Refresh();
    }

    private void Refresh()
    {
        ControlProperties.RemoveAllChildren();

        if (SelectedControl == null)
            return;

        var props = GuiDumpCommand.PropertyValuesForInheritance(SelectedControl);
        foreach (var (classname, values) in props)
        {
            ControlProperties.AddChild(new PanelContainer
            {
                Children = { new Label
                {
                    Text = classname,
                    Margin = new Thickness(3, 2)
                }},
                PanelOverride = new StyleBoxFlat
                {
                    BorderThickness = new Thickness(0, 1),
                    BorderColor = Color.Gray,
                    BackgroundColor = Color.FromHex("#555555"),
                }
            });
            foreach (var (prop, value) in values)
            {
                var button = new ContainerButton
                {
                    Children =
                    {
                        new BoxContainer
                        {
                            Orientation = BoxContainer.LayoutOrientation.Horizontal,
                            SeparationOverride = 3,
                            Margin = new Thickness(3, 1),
                            Children =
                            {
                                new BoxContainer
                                {
                                    Orientation = BoxContainer.LayoutOrientation.Horizontal,
                                    Children =
                                    {
                                        new Label { Text = $"{prop}", FontColorOverride = Color.GreenYellow },
                                        new Label { Text = ":" }, // this is for the non colored ":", intentional
                                    }
                                },
                                new Label { Text = $"{value}" },
                            }
                        }
                    }
                };
                button.OnPressed += _ =>
                {
                    // TODO replace with parenting to popup container on WindowRoot
                    UIPopup.Text = GuiDumpCommand.PropertyValuesString(SelectedControl, prop);
                    var box = UIBox2.FromDimensions(UserInterfaceManager.MousePositionScaled.Position
                                                    - GlobalPosition, Vector2.One);
                    UIPopup.Open(box);
                };
                ControlProperties.AddChild(button);
            }
        }
    }
}
