using System.Text;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using Robust.Shared.Utility;

namespace Robust.Client.UserInterface.CustomControls.DebugMonitorControls
{
    internal sealed class DebugCoordsPanel : PanelContainer
    {
        [Dependency] private readonly IPlayerManager _playerManager = default!;
        [Dependency] private readonly IEyeManager _eyeManager = default!;
        [Dependency] private readonly IInputManager _inputManager = default!;
        [Dependency] private readonly IEntityManager _entityManager = default!;
        [Dependency] private readonly IClyde _displayManager = default!;
        [Dependency] private readonly IMapManager _mapManager = default!;
        [Dependency] private readonly IBaseClient _baseClient = default!;

        private readonly StringBuilder _textBuilder = new();
        private readonly char[] _textBuffer = new char[1024];

        private readonly Label _contents;

        public DebugCoordsPanel()
        {
            IoCManager.InjectDependencies(this);

            HorizontalAlignment = HAlignment.Left;

            _contents = new Label
            {
                FontColorShadowOverride = Color.Black
            };
            AddChild(_contents);

            PanelOverride = new StyleBoxFlat
            {
                BackgroundColor = new Color(67, 105, 255, 138),
                ContentMarginLeftOverride = 5,
                ContentMarginTopOverride = 5
            };

            MouseFilter = _contents.MouseFilter = MouseFilterMode.Ignore;
            MinWidth = 175;
        }

        protected override void FrameUpdate(FrameEventArgs args)
        {
            if (!VisibleInTree)
            {
                return;
            }

            _textBuilder.Clear();

            var isInGame = _baseClient.RunLevel.IsInGameLike();
            var mouseScreenPos = _inputManager.MouseScreenPosition;
            var screenSize = _displayManager.ScreenSize;
            var screenScale = _displayManager.MainWindow.ContentScale;

            EntityCoordinates mouseGridPos = default;
            TileRef tile = default;
            MapCoordinates mouseWorldMap = default;

            if (isInGame)
            {
                mouseWorldMap = _eyeManager.PixelToMap(mouseScreenPos);
                if (mouseWorldMap != MapCoordinates.Nullspace)
                {
                    var mapSystem = _entityManager.System<SharedMapSystem>();
                    var xformSystem = _entityManager.System<SharedTransformSystem>();

                    if (_mapManager.TryFindGridAt(mouseWorldMap, out var mouseGridUid, out var mouseGrid))
                    {
                        mouseGridPos = mapSystem.MapToGrid(mouseGridUid, mouseWorldMap);
                        tile = mapSystem.GetTileRef(mouseGridUid, mouseGrid, mouseGridPos);
                    }
                    else
                    {
                        mouseGridPos = new EntityCoordinates(mapSystem.GetMapOrInvalid(mouseWorldMap.MapId),
                            mouseWorldMap.Position);
                        tile = new TileRef(EntityUid.Invalid,
                            mouseGridPos.ToVector2i(_entityManager, _mapManager, xformSystem), Tile.Empty);
                    }
                }
            }

            var controlHovered = UserInterfaceManager.CurrentlyHovered;

            _textBuilder.Append($@"Positioning Debug:
Screen Size: {screenSize} (scale: {screenScale})
Mouse Pos:
    Screen: {mouseScreenPos}
    {mouseWorldMap}
    {_entityManager.GetNetCoordinates(mouseGridPos)}
    {tile}
    GUI: {controlHovered}");

            if (isInGame)
            {
                var xformSystem = _entityManager.System<SharedTransformSystem>();

                _textBuilder.AppendLine("\nAttached NetEntity:");
                var controlledEntity = _playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid;

                if (controlledEntity == EntityUid.Invalid)
                {
                    _textBuilder.AppendLine("No attached netentity.");
                }
                else
                {
                    var entityTransform = _entityManager.GetComponent<TransformComponent>(controlledEntity);
                    var playerWorldOffset = xformSystem.GetMapCoordinates(entityTransform);
                    var playerScreen = _eyeManager.WorldToScreen(playerWorldOffset.Position);

                    var playerCoordinates = entityTransform.Coordinates;
                    var playerRotation = xformSystem.GetWorldRotation(entityTransform);
                    var gridRotation = entityTransform.GridUid != null
                        ? xformSystem.GetWorldRotation(entityTransform.GridUid.Value)
                        : Angle.Zero;

                    _textBuilder.Append($@"    Screen: {playerScreen}
    {playerWorldOffset}
    {_entityManager.GetNetCoordinates(playerCoordinates)}
    Rotation: {playerRotation.Degrees:F2}°
    NEntId: {_entityManager.GetNetEntity(controlledEntity)}
    Grid NEntId: {_entityManager.GetNetEntity(entityTransform.GridUid)}
    Grid Rotation: {gridRotation.Degrees:F2}°");
                }
            }

            _contents.TextMemory = FormatHelpers.BuilderToMemory(_textBuilder, _textBuffer);
        }
    }
}
