using System;
using System.Linq;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Clyde;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Utility;

namespace Robust.Client.UserInterface;

/// <summary>
/// Shows all loaded textures in the game.
/// </summary>
[GenerateTypedNameReferences]
internal sealed partial class DevWindowTabTextures : Control
{
    [Dependency] private IClydeInternal _clyde = null!;
    [Dependency] private ILocalizationManager _loc = null!;

    public DevWindowTabTextures()
    {
        RobustXamlLoader.Load(this);
        IoCManager.InjectDependencies(this);

        ReloadButton.OnPressed += _ => Reload();
        SearchBar.OnTextChanged += _ => Reload();
    }

    protected override void VisibilityChanged(bool newVisible)
    {
        if (newVisible)
        {
            Reload();
        }
        else
        {
            // Clear to release memory when tab not visible.
            Clear();
        }
    }

    private void Clear()
    {
        TextureList.RemoveAllChildren();
    }

    private void Reload()
    {
        Clear();

        var total = 0L;

        foreach (var (clydeTexture, loadedTexture) in _clyde.GetLoadedTextures()
                     .OrderByDescending(tup => tup.Item2.MemoryPressure))
        {
            if (!string.IsNullOrWhiteSpace(SearchBar.Text))
            {
                if (loadedTexture.Name is not { } name)
                    continue;

                if (!name.Contains(SearchBar.Text, StringComparison.CurrentCultureIgnoreCase))
                    continue;
            }

            if (loadedTexture.MemoryPressure == 0)
            {
                // Bad hack to avoid showing render targets lol.
                continue;
            }

            var button = new ContainerButton
            {
                Children = { new TextureEntry(loadedTexture, clydeTexture) }
            };
            button.OnPressed += _ => SelectTexture(loadedTexture, clydeTexture);

            TextureList.AddChild(button);

            total += loadedTexture.MemoryPressure;
        }

        SummaryLabel.Text =
            _loc.GetString("dev-window-tab-textures-summary", ("bytes", ByteHelpers.FormatBytes(total)));
    }

    private void SelectTexture(Clyde.LoadedTexture loaded, Clyde.ClydeTexture texture)
    {
        SelectedTextureDisplay.Texture = texture;
        SelectedTextureInfo.Text = _loc.GetString("dev-window-tab-textures-info",
            ("width", loaded.Width),
            ("height", loaded.Height),
            ("pixelType", loaded.TexturePixelType),
            ("srgb", loaded.IsSrgb),
            ("name", loaded.Name ?? ""),
            ("bytes", ByteHelpers.FormatBytes(loaded.MemoryPressure)));
    }

    private sealed class TextureEntry : Control
    {
        public TextureEntry(Clyde.LoadedTexture loaded, Clyde.ClydeTexture texture)
        {
            SetHeight = 64;

            var bytes = ByteHelpers.FormatBytes(loaded.MemoryPressure);

            var label = loaded.Name == null
                ? $"{texture.TextureId} ({bytes})"
                : $"{loaded.Name}\n{texture.TextureId} ({bytes})";

            AddChild(new BoxContainer
            {
                Orientation = BoxContainer.LayoutOrientation.Horizontal,
                Children =
                {
                    new TextureRect
                    {
                        SetWidth = 64,
                        Texture = texture,
                        CanShrink = true,
                        RectClipContent = true,
                        Stretch = TextureRect.StretchMode.Scale
                    },
                    new Label
                    {
                        Text = label,
                        ClipText = true,
                        HorizontalExpand = true
                    }
                }
            });
        }
    }
}
