using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Myra;
using Myra.Graphics2D.Brushes;
using Myra.Graphics2D.TextureAtlases;
using Myra.Graphics2D.UI;
using Myra.Graphics2D.UI.File;
using Newtonsoft.Json;
using Sledgemapper.Shared.Entities;
using Sledgemapper.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Sledgemapper
{
    public class Sledgemapper : Game
    {
        private readonly CommunicationManager _communicationManager;
        private readonly State _state;
        private readonly GraphicsDeviceManager _graphics;
        private SpriteBatch _spriteBatch;
        private readonly Desktop _desktop;
        private KeyboardState oldState;
        private MouseState oldMouseState;
        private Vector3 _viewportCenter = new(0, 0, 0);
        private Dictionary<string, SpriteFont> _fonts;
        private readonly Session _sessionData;
        private AuthenticateResponse _authResponse;
        private MainWidget _mainWidget;

        public Sledgemapper()
        {
            _graphics = new GraphicsDeviceManager(this);

            _graphics.GraphicsProfile = GraphicsProfile.Reach;
            _graphics.PreferMultiSampling = false;

            Content.RootDirectory = "Content";
            _desktop = new Desktop();
            MyraEnvironment.Game = this;
            _sessionData = new Session();
            IsFixedTimeStep = false;
            _communicationManager = new CommunicationManager(_sessionData);
            _state = new State();
        }

        protected override void Initialize()
        {
            IsMouseVisible = true;
            Window.AllowUserResizing = true;
            base.Initialize();
        }

        private void AddItemToToolGrid(Grid grid, EventHandler eventAction, string folder)
        {
            var tilesFolderContent = Content.LoadContentFolder<Texture2D>(folder);
            var indexX = 0;
            var indexY = 0;
            foreach (var item in tilesFolderContent)
            {
                var tileButton = new ImageButton { Image = new TextureRegion(item.Value), GridColumn = indexY, GridRow = indexX, Id = item.Key, Width = 40, Height = 40 };
                tileButton.Click += eventAction;
                grid.Widgets.Add(tileButton);
                indexY++;
                if (indexY == 4)
                {
                    indexY = 0;
                    indexX++;
                }
            }
        }

        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(GraphicsDevice);
            MyraEnvironment.Game = this;

            _mainWidget = new MainWidget();

            _mainWidget.MenuConnectSync.Selected += OnMenuConnectSyncSelected;
            _mainWidget.MenuFileLoad.Selected += OnMenuFileLoadSelected;
            _mainWidget.MenuFileSave.Selected += OnMenuFileSaveSelected;
            _mainWidget.MenuConnectLogin.Selected += OnMenuConnectLoginSelected;
            _mainWidget.MenuConnectNew.Selected += OnMenuConnectNewSelected;
            _mainWidget.MenuConnectJoin.Selected += OnMenuConnectJoinSelected;
            _mainWidget.MenuConnectUpload.Selected += OnMenuConnectUploadSelected;
            _mainWidget.MenuConnectNew.Enabled = false;
            _mainWidget.MenuConnectJoin.Enabled = false;
            _mainWidget.MenuConnectSync.Enabled = false;
            _mainWidget.MenuConnectUpload.Enabled = false;

            AddItemToToolGrid(_mainWidget.GridTiles, OnTileButtonClicked, "tiles");
            AddItemToToolGrid(_mainWidget.GridWalls, OnWallButtonClicked, "walls");
            AddItemToToolGrid(_mainWidget.GridOverlays, OnOverlayButtonClicked, "overlays");

            _fonts = Content.LoadContentFolder<SpriteFont>("fonts");

            _desktop.Root = _mainWidget;
        }

        protected override void Update(GameTime gameTime)
        {
            KeyboardState newState = Keyboard.GetState();

            if (IsActive && GraphicsDevice.Viewport.Bounds.Contains(Mouse.GetState().Position) && !_desktop.IsMouseOverGUI && !_desktop.HasModalWidget)
            {
                var mouseState = Mouse.GetState();

                var screenPosition = new Point(mouseState.Position.X - (int)_viewportCenter.X, mouseState.Position.Y - (int)_viewportCenter.Y);

                _state._hoveredTile.X = screenPosition.X / _state._tileSize;
                _state._hoveredTile.Y = screenPosition.Y / _state._tileSize;
                if (screenPosition.X < 0)
                {
                    _state._hoveredTile.X--;
                }

                if (screenPosition.Y < 0)
                {
                    _state._hoveredTile.Y--;
                }

                if (_state._insertMode == InsertMode.Wall)
                {
                    _state.SelectClosestWall(screenPosition);
                }

                if (_state._insertMode == InsertMode.Overlay)
                {
                    _state.SelectOverlay(screenPosition);
                }

                if (mouseState.LeftButton == ButtonState.Pressed && mouseState.LeftButton != oldMouseState.LeftButton)
                {
                    _state._selectedTile.X = _state._hoveredTile.X;
                    _state._selectedTile.Y = _state._hoveredTile.Y;
                    _communicationManager.Connection?.SendAsync("UpdatePosition", _sessionData.SessionName, _sessionData.SessionId, _state._selectedTile);
                }

                if (newState.IsKeyDown(Keys.LeftControl)
                && mouseState.LeftButton == ButtonState.Pressed
                && ((mouseState.LeftButton != oldMouseState.LeftButton) || (_state._selectedTile.X != _state._hoveredTile.X && _state._selectedTile.Y != _state._hoveredTile.Y)))
                {
                    switch (_state._insertMode)
                    {
                        case InsertMode.Tile:
                            _state._selectedTile.X = _state._hoveredTile.X;
                            _state._selectedTile.Y = _state._hoveredTile.Y;
                            _communicationManager.Connection?.SendAsync("UpdatePosition", _sessionData.SessionName, _sessionData.SessionId, _state._selectedTile);

                            _sessionData.NewTile(_state._selectedTile, _state._currentTileId);
                            break;

                        case InsertMode.Wall:
                            _sessionData.NewWall(_state._selectedWall, _state._currentWallId);

                            break;
                        case InsertMode.Overlay:
                            _sessionData.NewOverlay(_state._selectedOverlay, _state._currentOverlayId);
                            break;
                    }
                }

                if (!newState.IsKeyDown(Keys.LeftControl) && mouseState.LeftButton == ButtonState.Pressed && mouseState.LeftButton == oldMouseState.LeftButton)
                {
                    _viewportCenter = new Vector3(_viewportCenter.X + mouseState.Position.X - oldMouseState.Position.X, _viewportCenter.Y + mouseState.Position.Y - oldMouseState.Position.Y, 0);
                }

                if (newState.IsKeyDown(Keys.LeftControl) && mouseState.ScrollWheelValue != oldMouseState.ScrollWheelValue)
                {
                    if (mouseState.ScrollWheelValue > oldMouseState.ScrollWheelValue)
                    {
                        _state._tileSize = Math.Min(120, _state._tileSize + 10);

                    }
                    else if (mouseState.ScrollWheelValue < oldMouseState.ScrollWheelValue)
                    {
                        _state._tileSize = Math.Max(10, _state._tileSize - 10);
                    }
                }

                oldMouseState = mouseState;
            }


            if (newState.IsKeyDown(Keys.Delete))
            {
                switch (_state._insertMode)
                {
                    case InsertMode.Tile:
                        _state._selectedTile.X = _state._hoveredTile.X;
                        _state._selectedTile.Y = _state._hoveredTile.Y;
                        _sessionData.DeleteTile(_state._selectedTile);
                        break;
                    case InsertMode.Wall:
                        _sessionData.DeleteWall(_state._selectedWall);
                        break;
                    case InsertMode.Overlay:
                        _sessionData.DeleteOverlay(_state._selectedOverlay);
                        break;
                }
            }

            foreach (var key in newState.GetPressedKeys())
            {
                switch (key)
                {
                    case Keys.Left:
                        if (oldState.IsKeyUp(Keys.Left) && newState.IsKeyDown(Keys.Left))
                        { _state._selectedTile.X--; }
                        break;
                    case Keys.Right:
                        if (oldState.IsKeyUp(Keys.Right) && newState.IsKeyDown(Keys.Right))
                        { _state._selectedTile.X++; }
                        break;
                    case Keys.Up:
                        if (oldState.IsKeyUp(Keys.Up) && newState.IsKeyDown(Keys.Up))
                        { _state._selectedTile.Y--; }
                        break;
                    case Keys.Down:
                        if (oldState.IsKeyUp(Keys.Down) && newState.IsKeyDown(Keys.Down))
                        { _state._selectedTile.Y++; }
                        break;
                }
                _communicationManager.Connection?.SendAsync("UpdatePosition", _sessionData.SessionName, _state._selectedTile);

            }

            oldState = newState;

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            if (_spriteBatch is null)
            {
                return;
            }
            GraphicsDevice.Clear(Color.LightGray);

            var visibleTilesX = GraphicsDevice.Viewport.Width / _state._tileSize + 1;
            var visibleTilesY = GraphicsDevice.Viewport.Height / _state._tileSize + 1;

            _spriteBatch.Begin(transformMatrix: Matrix.CreateTranslation(_viewportCenter));

            DrawGrid(visibleTilesX, visibleTilesY);
            DrawTiles();
            DrawWalls();
            DrawOverlays();

            if (string.IsNullOrWhiteSpace(_sessionData.SessionName))
            {
                _spriteBatch.DrawRectangle(new Rectangle((_state._selectedTile.X * _state._tileSize) - 2, (_state._selectedTile.Y * _state._tileSize) - 2, _state._tileSize + 3, _state._tileSize + 3), Color.Red, 2);
            }

            DrawPlayers();

            var startWall = new Vector2(_state._selectedWall.X * _state._tileSize, _state._selectedWall.Y * _state._tileSize);
            if (_state._insertMode == InsertMode.Wall)
            {
                _spriteBatch.DrawLine(startWall, _state._tileSize, MathHelper.ToRadians(90 * _state._selectedWall.Rotation), Color.Red, 2);
            }

            var overlay = new Vector2(_state._selectedOverlay.X * _state._tileSize, _state._selectedOverlay.Y * _state._tileSize);
            if (_state._insertMode == InsertMode.Overlay && _state._selectedOverlay.Intersection)
            {
                _spriteBatch.DrawCircle(overlay, _state._tileSize / 3f, 100, Color.Red, 2);
            }

            _spriteBatch.End();

            _desktop?.Render();
            base.Draw(gameTime);
        }

        private void DrawGrid(int visibleTilesX, int visibleTilesY)
        {
            for (var i = -1; i < visibleTilesX + 2; i++)
            {
                var posX1 = i * _state._tileSize - _viewportCenter.X;
                var posY1 = -_viewportCenter.Y;
                posX1 -= posX1 % _state._tileSize;
                posY1 -= posY1 % _state._tileSize;
                var posX2 = i * _state._tileSize - _viewportCenter.X;
                var posY2 = GraphicsDevice.Viewport.Height - _viewportCenter.Y;
                posX2 -= posX2 % _state._tileSize;
                posY2 -= posY2 % _state._tileSize;

                _spriteBatch.DrawLine(
                   posX1, posY1,
                    posX2,
                    posY2,
                    Color.GhostWhite);
            }

            for (var i = -1; i < visibleTilesY + 2; i++)
            {
                var posX1 = -_viewportCenter.X;
                var posY1 = i * _state._tileSize - _viewportCenter.Y;
                posX1 -= posX1 % _state._tileSize;
                posY1 -= posY1 % _state._tileSize;
                var posX2 = GraphicsDevice.Viewport.Width - _viewportCenter.X;
                var posY2 = i * _state._tileSize - _viewportCenter.Y;
                posX2 -= posX2 % _state._tileSize;
                posY2 -= posY2 % _state._tileSize;

                _spriteBatch.DrawLine(posX1, posY1,
                    posX2,
                    posY2,
                 Color.GhostWhite);
            }
        }

        private void DrawOverlays()
        {
            foreach (var tile in _sessionData.Overlays.Values)
            {
                var content = Content.Load<Texture2D>($"overlays/{tile.ID}");
                if (tile.Intersection)
                {
                    var posX = tile.X * _state._tileSize;
                    var posY = tile.Y * _state._tileSize;

                    _spriteBatch.Draw(content, new Vector2(posX, posY),
                    null, new Color(24, 118, 157), MathHelper.ToRadians(90 * tile.Rotation), new Vector2(content.Width / 2, content.Height / 2), ((float)_state._tileSize - 10) / content.Width, SpriteEffects.None, 0);
                }
                else
                {
                    var posX = tile.X * _state._tileSize + _state._tileSize / 2f;
                    var posY = tile.Y * _state._tileSize + _state._tileSize / 2f;

                    _spriteBatch.Draw(content, new Vector2(posX, posY),
                    null, new Color(24, 118, 157), MathHelper.ToRadians(90 * tile.Rotation), new Vector2(content.Width / 2, content.Height / 2), ((float)_state._tileSize - 10) / content.Width, SpriteEffects.None, 0);
                }
            }
        }

        private void DrawPlayers()
        {
            foreach (var player in _sessionData.Players.Copy())
            {
                var hexs = player.Color.TrimStart('#').Split(2).ToArray();
                var color = new Color(int.Parse(hexs[0], System.Globalization.NumberStyles.HexNumber),
                int.Parse(hexs[1], System.Globalization.NumberStyles.HexNumber),
                int.Parse(hexs[2], System.Globalization.NumberStyles.HexNumber));
                _spriteBatch.DrawRectangle(new Rectangle(player.Position.X * _state._tileSize, player.Position.Y * _state._tileSize, _state._tileSize - 1, _state._tileSize - 1), color, 2);

                var ffont = _fonts.FirstOrDefault(m => int.Parse(m.Key.Replace("font", "")) > _state._tileSize).Value ?? _fonts.Last().Value;

                var fscale = _state._tileSize / ((float)ffont.LineSpacing * 2);
                _spriteBatch.DrawString(ffont,
                player.Initials,
                new Vector2(player.Position.X * _state._tileSize + 2, player.Position.Y * _state._tileSize + _state._tileSize - 2 - ffont.LineSpacing * fscale),
                color,
                0,
                Vector2.Zero,
                fscale,
                SpriteEffects.None,
                0);
            }
        }

        private void DrawTiles()
        {
            foreach (var tile in _sessionData.Map.Values)
            {
                var content = Content.Load<Texture2D>($"tiles/{tile.ID}");

                var posX = tile.X * _state._tileSize + _state._tileSize / 2f;
                var posY = tile.Y * _state._tileSize + _state._tileSize / 2f;

                _spriteBatch.Draw(content, new Vector2(posX, posY),
                null, Color.White, MathHelper.ToRadians(90 * tile.Rotation), new Vector2(content.Width / 2, content.Height / 2), ((float)_state._tileSize - 1) / content.Width, SpriteEffects.None, 0);
            }
        }

        private void DrawWalls()
        {
            foreach (var wall in _sessionData.Walls.Values)
            {
                var content = Content.Load<Texture2D>($"walls/{wall.ID}");
                var scale = _state._tileSize / (float)content.Height;
                var offset = scale * content.Width / 2f;
                var posX = wall.X * _state._tileSize;
                var posY = wall.Y * _state._tileSize;
                if (wall.Rotation == 1)
                {
                    posX -= (int)offset;
                }
                else if (wall.Rotation == 0)
                {
                    posY += (int)offset;
                }
                _spriteBatch.Draw(content, new Vector2(posX, posY), null, Color.White, MathHelper.ToRadians(90 * (wall.Rotation - 1)), new Vector2(0, 0), scale, SpriteEffects.None, 0);
            }
        }

        private async void OnButtonJoinSessionClicked(object sender, EventArgs e)
        {
            Container container = ((TextButton)sender).Parent;
            while (!(container is Window))
            {
                container = container.Parent;
            }
            var localWindow = (Window)container;
            var localContent = localWindow.Content as SessionWindow;
            var isValid = ValidateTextbox(localContent.TxtSession);
            if (!isValid)
            {
                return;
            }

            if (_communicationManager.Connection.State != HubConnectionState.Connected)
            {
                await _communicationManager.Connection.StartAsync();
            }

            var successful = false;
            try
            {
                var result = await _communicationManager.Connection?.InvokeAsync<Session>("JoinSession", localContent.TxtSession.Text);
                if (result != null)
                {
                    _sessionData.Map = result.Map;
                    _sessionData.Walls = result.Walls;
                    _sessionData.Overlays = result.Overlays;

                    _sessionData.MapEntityAdded -= OnMapEntityAdded;
                    _sessionData.MapEntityDeleted -= OnMapEntityDeleted;
                    _sessionData.MapEntityAdded += OnMapEntityAdded;
                    _sessionData.MapEntityDeleted += OnMapEntityDeleted;
                    _sessionData.SessionId = result.SessionId;
                    _sessionData.SessionName = result.SessionName;
                }
                successful = result != null;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            if (successful)
            {
                _sessionData.SessionName = localContent.TxtSession.Text;
                localWindow.Close();
            }
        }

        private async void OnButtonNewSessionClicked(object sender, EventArgs e)
        {
            Container container = ((TextButton)sender).Parent;
            while (!(container is Window))
            {
                container = container.Parent;
            }
            var localWindow = (Window)container;
            var localContent = localWindow.Content as SessionWindow;
            var isValid = ValidateTextbox(localContent.TxtSession);
            if (!isValid)
            {
                return;
            }

            if (_communicationManager.Connection.State != HubConnectionState.Connected)
            {
                await _communicationManager.Connection.StartAsync();
            }

            var successful = false;
            try
            {
                var result = await _communicationManager.Api.NewSession(localContent.TxtSession.Text);

                if (result)
                {
                    _sessionData.SessionName = localContent.TxtSession.Text;
                    _sessionData.MapEntityAdded -= OnMapEntityAdded;
                    _sessionData.MapEntityDeleted -= OnMapEntityDeleted;
                    _sessionData.MapEntityAdded += OnMapEntityAdded;
                    _sessionData.MapEntityDeleted += OnMapEntityDeleted;
                }
                successful = result;
                var result2 = await _communicationManager.Connection?.InvokeAsync<Session>("JoinSession", localContent.TxtSession.Text);
                _sessionData.SessionId = result2.SessionId;
                _sessionData.SessionName = localContent.TxtSession.Text;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            if (successful)
            {
                _sessionData.SessionName = localContent.TxtSession.Text;
                _communicationManager.SessionData.Map = _sessionData.Map;
                _communicationManager.SessionData.Overlays = _sessionData.Overlays;
                _communicationManager.SessionData.Walls = _sessionData.Walls;

                localWindow.Close();
            }
        }

        private async void OnButtonLoginClick(object sender, EventArgs e)
        {
            Container container = ((TextButton)sender).Parent;
            while (!(container is Window))
            {
                container = container.Parent;
            }

            var localWindow = (Window)container;
            var localContent = localWindow.Content as LoginRegisterWindow;
            var isValid = true;
            isValid &= ValidateTextbox(localContent.TxtEmail);
            isValid &= ValidateTextbox(localContent.TxtPassword);

            if (!isValid)
            {
                return;
            }

            var successful = false;
            try
            {

                _authResponse = await _communicationManager.Login(new AuthenticateModel
                {
                    Username = localContent.TxtEmail.Text,
                    Password = localContent.TxtPassword.Text
                });
                successful = _authResponse != null;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            if (successful)
            {
                _mainWidget.MenuConnectNew.Enabled = true;
                _mainWidget.MenuConnectJoin.Enabled = true;
                _mainWidget.MenuConnectSync.Enabled = true;
                localWindow.Close();
            }
        }

        private async void OnButtonRegisterClick(object sender, EventArgs e)
        {
            Container container = ((TextButton)sender).Parent;
            while (!(container is Window))
            {
                container = container.Parent;
            }

            var localWindow = (Window)container;
            var localContent = localWindow.Content as LoginRegisterWindow;
            var isValid = true;
            isValid &= ValidateTextbox(localContent.TxtEmail);
            isValid &= ValidateTextbox(localContent.TxtPassword);
            isValid &= ValidateTextbox(localContent.TxtFirstname);
            isValid &= ValidateTextbox(localContent.TxtLastname);
            isValid &= ValidateTextbox(localContent.TxtInitials);

            if (!isValid)
            {
                return;
            }

            var successful = false;
            try
            {
                var result = await _communicationManager.Register(new RegisterModel
                {
                    Username = localContent.TxtEmail.Text,
                    Password = localContent.TxtPassword.Text,
                    FirstName = localContent.TxtFirstname.Text,
                    LastName = localContent.TxtLastname.Text,
                    Initials = localContent.TxtInitials.Text
                });
                if (result)
                {
                    _authResponse = await _communicationManager.Login(new AuthenticateModel
                    {
                        Username = localContent.TxtEmail.Text,
                        Password = localContent.TxtPassword.Text
                    });
                    successful = true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            if (successful)
            {
                _mainWidget.MenuConnectNew.Enabled = true;
                _mainWidget.MenuConnectJoin.Enabled = true;
                _mainWidget.MenuConnectSync.Enabled = true;
                localWindow.Close();
            }
        }

        private void OnOverlayButtonClicked(object sender, EventArgs e)
        {
            _state._currentOverlayId = ((ImageButton)sender).Id;
            _mainWidget.ClearSelection();
            ((ImageButton)sender).Border = new SolidBrush(Color.Red);
            ((ImageButton)sender).BorderThickness = new Myra.Graphics2D.Thickness(2);
            _state._insertMode = InsertMode.Overlay;
        }

        private void OnTileButtonClicked(object sender, EventArgs e)
        {
            _state._currentTileId = ((ImageButton)sender).Id;
            _mainWidget.ClearSelection();
            ((ImageButton)sender).Border = new SolidBrush(Color.Red);
            ((ImageButton)sender).BorderThickness = new Myra.Graphics2D.Thickness(2);
            _state._insertMode = InsertMode.Tile;
        }

        private void OnWallButtonClicked(object sender, EventArgs e)
        {
            _state._currentWallId = ((ImageButton)sender).Id;
            _mainWidget.ClearSelection();
            ((ImageButton)sender).Border = new SolidBrush(Color.Red);
            ((ImageButton)sender).BorderThickness = new Myra.Graphics2D.Thickness(2);
            _state._insertMode = InsertMode.Wall;
        }

        private void OnMenuConnectJoinSelected(object sender, EventArgs e)
        {
            Window window = new()
            {
                Title = "Join mapping session"
            };

            var content = new SessionWindow();
            content.BtnLogin.Text = "Join";
            content.BtnLogin.Click += OnButtonJoinSessionClicked;
            window.Content = content;

            window.ShowModal(_desktop);
        }

        private void OnMenuConnectLoginSelected(object sender, EventArgs e)
        {
            Window window = new()
            {
                Title = "Login"
            };

            var content = new LoginRegisterWindow();
            content.RdoLogin.IsPressed = true;
            content.RdoLogin.Click += (s, e) =>
            {
                content.TxtFirstname.Visible = false;
                content.TxtLastname.Visible = false;
                content.TxtInitials.Visible = false;
                content.LblFirstname.Visible = false;
                content.LblLastname.Visible = false;
                content.LblInitials.Visible = false;
                content.BtnLogin.Visible = true;
                content.BtnRegister.Visible = false;
                window.Title = "Login";
            };

            content.RdoRegister.Click += (s, e) =>
            {
                content.TxtFirstname.Visible = true;
                content.TxtLastname.Visible = true;
                content.TxtInitials.Visible = true;
                content.LblFirstname.Visible = true;
                content.LblLastname.Visible = true;
                content.LblInitials.Visible = true;
                content.BtnLogin.Visible = false;
                content.BtnRegister.Visible = true;
                window.Title = "Register";
            };

            content.BtnRegister.Click += OnButtonRegisterClick;
            content.BtnLogin.Click += OnButtonLoginClick;

            window.Content = content;
            window.ShowModal(_desktop);
        }

        private async void OnMenuConnectSyncSelected(object sender, EventArgs e)
        {
            var serverMap = await _communicationManager.Api.Session(_sessionData.SessionName);
            _sessionData.Overlays = serverMap.Overlays;
            _sessionData.Map = serverMap.Map;
            _sessionData.Walls = serverMap.Walls;
        }

        private async void OnMenuConnectUploadSelected(object sender, EventArgs e)
        {
            await _communicationManager.Api.SaveSnapshot(_sessionData, _sessionData.SessionName);
        }

        private void OnMenuConnectNewSelected(object sender, EventArgs e)
        {
            Window window = new()
            {
                Title = "New mapping session"
            };

            var content = new SessionWindow();
            content.BtnLogin.Text = "Join";
            content.BtnLogin.Click += OnButtonNewSessionClicked;
            window.Content = content;

            window.ShowModal(_desktop);
        }

        private void OnMenuFileSaveSelected(object sender, EventArgs e)
        {
            FileDialog dialog = new(FileDialogMode.SaveFile)
            {
                Filter = "*.map"
            };

            dialog.Closed += (s, a) =>
            {
                if (!dialog.Result)
                {
                    return;
                }

                using StreamWriter file = File.CreateText(dialog.FilePath);
                JsonSerializer serializer = new();
                serializer.Serialize(file, _sessionData);
            };

            dialog.ShowModal(_desktop);
        }

        private void OnMenuFileLoadSelected(object sender, EventArgs e)
        {
            var dialog = new FileDialog(FileDialogMode.OpenFile)
            {
                Filter = "*.map"
            };

            dialog.Closed += (s, a) =>
            {
                if (!dialog.Result)
                {
                    return;
                }
                using StreamReader file = File.OpenText(dialog.FilePath);
                JsonSerializer serializer = new();
                var  loadData = (Session)serializer.Deserialize(file, typeof(Session));
                _sessionData.Map=loadData.Map;
                _sessionData.Overlays=loadData.Overlays;
                _sessionData.Walls=loadData.Walls;
            };

            dialog.ShowModal(_desktop);
        }

        private void OnMapEntityAdded(object sender, MapEntityAddedEventArgs e)
        {
            _communicationManager.Enqueue(e.MapEntity, TileAction.Add);
        }

        private void OnMapEntityDeleted(object sender, MapEntityDeletedEventArgs e)
        {
            _communicationManager.Enqueue(e.MapEntity, TileAction.Delete);
        }

        private bool ValidateTextbox(TextBox textBox)
        {
            var valid = !string.IsNullOrWhiteSpace(textBox.Text);
            if (!valid)
            {
                textBox.Background = new SolidBrush(Color.PaleVioletRed);
            }
            return valid;
        }
    }
}
