using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Xna.Framework;
using Myra.Graphics2D.Brushes;
using Myra.Graphics2D.TextureAtlases;
using Myra.Graphics2D.UI;
using Myra.Graphics2D.UI.File;
using Myra.Graphics2D.UI.Properties;
using Newtonsoft.Json;
using Sentry;
using Sledgemapper.Messages;
using Sledgemapper.Shared.Entities;
using System;
using System.IO;
using System.Linq;
using TinyMessenger;
using Session = Sledgemapper.Shared.Entities.Session;

namespace Sledgemapper.UI
{
    public partial class MainWidget
    {
        private readonly CommunicationManager CommunicationManager;

        private readonly TinyMessengerHub _messenger;

        private readonly GameWindow Window;

        public MainWidget(CommunicationManager communicationManager, TinyMessengerHub messenger, GameWindow window)
        {
            BuildUI();

            CommunicationManager = communicationManager;
            Window = window;
            _messenger = messenger;
            MenuConnectLogin.Selected += OnMenuConnectLoginSelected;
            MenuConnectSync.Selected += OnMenuConnectSyncSelected;
            MenuFileLoad.Selected += OnMenuFileLoadSelected;
            MenuFileSave.Selected += OnMenuFileSaveSelected;
            MenuFileSettings.Selected += OneMenuFileSettingsSelected;
            //MenuConnectLogin.Selected += OnMenuConnectLoginSelected;
            //MenuConnectNew.Selected += OnMenuConnectNewSelected;
            MenuConnectJoin.Selected += OnMenuConnectJoinSelected;
            MenuConnectUpload.Selected += OnMenuConnectUploadSelected;
            MenuViewCenterOnSelection.Selected += OnMenuViewCenterOnSelectionSelected;
            MenuViewShowCellNUmbers.Selected += OnMenuViewShowCellNUmbersSelected;
            MenuViewShowNotes.Selected += OnMenuViewNotesSelected;

            MenuCampaingNew.Selected += OnMenuCampaignNew;
            MenuCampaignOpen.Selected += OnMenuCampaignOpen;
            MenuCampaignPlayers.Selected += OnMenuCampaignPlayersSelected;

            MenuMapOpen.Selected += OnMenuMapOpen;
            MenuMapNew.Selected += OnMenuMapNew;

            MenuConnectNew.Enabled = false;
            MenuConnectJoin.Enabled = false;
            MenuConnectSync.Enabled = false;
            MenuConnectUpload.Enabled = false;
            MenuCampaignOpen.Enabled = false;
            MenuCampaignPlayers.Enabled = false;
            MenuCampaingNew.Enabled = false;
            MenuMapNew.Enabled = false;
            MenuMapOpen.Enabled = false;
            BtnToolbarLine.Click += OnBtnToolbarLinClicked;
            BtnToolbarRoom.Click += OnBtnToolbarRoomClicked;
            BtnToolbarDelete.Click += OnBtnToolbarDeleteClicked;
            _messenger.Subscribe<LoginSuccesfulMessage>(OnLoginSuccesfulMessage);
            _messenger.Subscribe<SignalrConnectionUpdateMessage>(OnSignalrConnectionUpdateMessage);
            _messenger.Subscribe<MapOpenedMessage>(OnMapOpenedMessage);
            _messenger.Subscribe<CenterOnTileMessage>(OnCenterOnTileMessage);
        }

        private void OnCenterOnTileMessage(CenterOnTileMessage obj)
        {
            CenterOnTile(obj.X, obj.Y);

        }

        private void OnMapOpenedMessage(MapOpenedMessage obj)
        {
            lblSessionName.Text = CommunicationManager.SessionData.SessionName;
            MenuConnectSync.Enabled = true;
            MenuConnectUpload.Enabled = true;
            CommunicationManager.SessionData.MapEntityAdded -= OnMapEntityAdded;
            CommunicationManager.SessionData.MapEntityDeleted -= OnMapEntityDeleted;
            CommunicationManager.SessionData.MapEntityAdded += OnMapEntityAdded;
            CommunicationManager.SessionData.MapEntityDeleted += OnMapEntityDeleted;
        }

        private async void OnSignalrConnectionUpdateMessage(SignalrConnectionUpdateMessage obj)
        {
            lblConnectionStatus.Text = "Connecting";
            await CommunicationManager.Connection.StartAsync();
            UpdateConnectionState(CommunicationManager.Connection);
        }

        private void OnLoginSuccesfulMessage(LoginSuccesfulMessage obj)
        {
            MenuConnectNew.Enabled = true;
            MenuConnectJoin.Enabled = true;
            MenuCampaignOpen.Enabled = true;
            MenuCampaignPlayers.Enabled = true;
            MenuCampaingNew.Enabled = true;

            lblUsername.Text = $"{obj.UserName} - {obj.Initials}";
        }

        public void ClearSelection()
        {
            ClearSelection(GridWalls);
            ClearSelection(GridOverlays);
            ClearSelection(Toolbar);
        }

        private void ClearSelection(Grid grid)
        {
            foreach (var widget in grid.Widgets)
            {
                widget.Border = null;
            }
        }

        private void ClearSelection(HorizontalStackPanel grid)
        {
            foreach (var widget in grid.Widgets)
            {
                widget.Border = null;
            }
        }

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

            var content = new LoginRegisterWindow(CommunicationManager, window, _messenger);
            window.Content = content;
            window.ShowModal(Desktop);
        }


        private void OnMenuConnectNewSelected(object sender, EventArgs e)
        {
            if (!((MenuItem)sender).Enabled)
            {
                return;
            }

            Window window = new()
            {
                Title = "New mapping session"
            };

            var content = new SessionWindow(CommunicationManager, _messenger, window);
            window.Content = content;

            window.ShowModal(Desktop);
        }

        private void UpdateConnectionState(HubConnection connection)
        {
            switch (connection.State)
            {
                case HubConnectionState.Connected:
                    lblConnectionStatus.Text = "Connected";
                    break;
                case HubConnectionState.Connecting:
                    lblConnectionStatus.Text = "Connecting";
                    break;
                case HubConnectionState.Disconnected:
                    lblConnectionStatus.Text = "Disconnected";

                    break;
                case HubConnectionState.Reconnecting:
                    lblConnectionStatus.Text = "Reconnecting";

                    break;
            }
        }

        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 async void OnMenuConnectSyncSelected(object sender, EventArgs e)
        {
            if (!((MenuItem)sender).Enabled)
            {
                return;
            }

            var serverMap = await CommunicationManager.Api.Session(CommunicationManager.SessionData.SessionName);
            CommunicationManager.SessionData.Overlays = serverMap.Overlays;
            CommunicationManager.SessionData.Map = serverMap.Map;
            CommunicationManager.SessionData.Walls = serverMap.Walls;
            CommunicationManager.SessionData.Notes = serverMap.Notes;
            CommunicationManager.SessionData.Lines = serverMap.Lines;
            CommunicationManager.SessionData.Rooms = serverMap.Rooms;
        }

        private async void OnMenuConnectUploadSelected(object sender, EventArgs e)
        {
            if (!((MenuItem)sender).Enabled)
            {
                return;
            }

            await CommunicationManager.Api.SaveSnapshot(CommunicationManager.SessionData, CommunicationManager.SessionData.SessionName);
        }

        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, CommunicationManager.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));
                CommunicationManager.SessionData.Map = loadData.Map;
                CommunicationManager.SessionData.Overlays = loadData.Overlays;
                CommunicationManager.SessionData.Walls = loadData.Walls;
                CommunicationManager.SessionData.Rooms = loadData.Rooms;
                CommunicationManager.SessionData.Lines = loadData.Lines;
            };

            dialog.ShowModal(Desktop);
        }

        private void OneMenuFileSettingsSelected(object sender, EventArgs e)
        {
            var propertyGrid = new PropertyGrid
            {
                Object = Settings.Instance,
                Width = 350
            };

            var _windowEditor = new Window
            {
                Title = "Object Editor",
                Content = propertyGrid
            };
            _windowEditor.ShowModal(Desktop);
        }

        private void OnMenuConnectJoinSelected(object sender, EventArgs e)
        {
            if (!((MenuItem)sender).Enabled)
            {
                return;
            }

            Window window = new()
            {
                Title = "Join mapping session"
            };

            var content = new SessionWindow(CommunicationManager, _messenger, window);

            window.Content = content;

            window.ShowModal(Desktop);
        }

        private void OnMenuViewShowCellNUmbersSelected(object sender, EventArgs e)
        {
            State.Instance.ShowCellNumbers = !State.Instance.ShowCellNumbers;
        }

        private void OnMenuViewCenterOnSelectionSelected(object sender, EventArgs e)
        {
            CenterOnSelectedTile();
        }

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

            var content = new NoteList(CommunicationManager, _messenger, window);

            for (var i = 0; i < CommunicationManager.SessionData.Notes.Values.Count; i++)
            {
                var note = CommunicationManager.SessionData.Notes.Values.ElementAt(i);
                var item = new NoteListItem();
                item.LblNoteText.Text = $"{note.ToString()} - {note.Text}";
                item.BtnNoteCenter.Image = new TextureRegion(CachedContent.Instance.Location);
                item.BtnNoteView.Image = new TextureRegion(CachedContent.Instance.Eye);
                item.BtnNoteCenter.Click += (s, e) => { CenterOnTile(note.X, note.Y); };
                item.BtnNoteView.Click += (s, e) => { EditNote(note); window.Close(); };
                content.StackNotesList.AddChild(item);
            }

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

        private void CenterOnSelectedTile()
        {
            CenterOnTile(State.Instance.SelectedTile.X, State.Instance.SelectedTile.Y);
        }

        private void CenterOnTile(int x, int y)
        {

            var center = new Point((Window.ClientBounds.Width + 200) / 2 - State.Instance.TileSize / 2, Window.ClientBounds.Height / 2 - State.Instance.TileSize / 2);
            var dx = center.X - x * State.Instance.TileSize - State.Instance.ViewportCenter.X;
            var dy = center.Y - y * State.Instance.TileSize - State.Instance.ViewportCenter.Y;
            State.Instance.ViewportCenter = new Vector3(State.Instance.ViewportCenter.X + dx, State.Instance.ViewportCenter.Y + dy, State.Instance.ViewportCenter.Z);

        }

        private void OnMenuCampaignNew(object sender, EventArgs e)
        {
            if (sender is MenuItem && !((MenuItem)sender).Enabled)
            {
                return;
            }

            Window window = new()
            {
                Title = "New campaign"
            };

            var content = new CampaignWindow();
        }

        private async void OnMenuCampaignOpen(object sender, EventArgs e)
        {
            if (!((MenuItem)sender).Enabled)
            {
                return;
            }

            Window window = new()
            {
                Title = "Campaigns"
            };

            var content = new CampaignList(CommunicationManager, window, _messenger, Settings.Instance, Desktop);
            await content.LoadCampaigns();

            window.Content = content;

            window.ShowModal(Desktop);
        }

        private void OnMapSelected(object sender, EventArgs e)
        {
            var item = sender as UI.ListItem;
            var localContent = item.GetParentContentInWindow<Widget>();

            var list = item.Parent as Myra.Graphics2D.UI.Grid;
            for (var i = 0; i < list.ChildrenCount; i++)
            {
                var currentItem = list.GetChild(i) as HorizontalStackPanel;// UI.ListItem;
                currentItem.Background = new SolidBrush("#D9D9D9FF");
            }
            item.Background = new SolidBrush(Settings.Instance.OverlayTintColor);
        }

        private async void OnMenuCampaignPlayersSelected(object sender, EventArgs e)
        {
            if (!((MenuItem)sender).Enabled)
            {
                return;
            }

            Window window = new()
            {
                Title = "Players"
            };

            var content = new PlayerList();
            var players = await CommunicationManager.Api.GetPlayers(State.Instance.CampaignName);
            foreach (var player in players)
            {
                var item = new UI.ListItem();
                item.ItemName.Text = player.UserName;


                content.StackCampaignsList.AddChild(item);
            }

            content.BtnInvitePlayer.Click += (s, e) =>
            {
                window.Close();
                ShowAddPLayerWindow();
            };

            window.Content = content;

            window.ShowModal(Desktop);
        }
        private async void OnMenuMapOpen(object sender, EventArgs e)
        {
            if (!((MenuItem)sender).Enabled)
            {
                return;
            }

            Window window = new()
            {
                Title = "Maps"
            };

            var content = new MapList();
            var campaigns = await CommunicationManager.Api.GetMaps(State.Instance.CampaignName);
            foreach (var campaign in campaigns)
            {
                var item = new UI.ListItem();
                item.ItemName.Text = campaign.SessionName;
                item.TouchUp += OnMapSelected;
                content.StackCampaignsList.AddChild(item);
            }

            content.BtnNewCampaign.Click += (s, e) =>
            {
                window.Close();
                OnMenuMapNew(s, e);
            };

            window.Content = content;

            window.ShowModal(Desktop);
        }

        private void ShowAddPLayerWindow()
        {
            Window window = new()
            {
                Title = "Invite player"
            };

            var content = new PlayerWindow();
            //content.BtnNewCampaign.Text = "N";
            content.BtnNewCampaign.Click += OnButtonInvitePlayerClicked;
            window.Content = content;

            window.ShowModal(Desktop);
            content.TxtCampaign.SetKeyboardFocus();
        }

        private async void OnButtonJoinSessionClicked(object sender, EventArgs e)
        {
            var localContent = ((TextButton)sender).GetParentContentInWindow<SessionWindow>();

            var isValid = localContent.Content.TxtSession.ValidateTextbox();
            if (!isValid)
            {
                return;
            }

            if (CommunicationManager.Connection.State != HubConnectionState.Connected)
            {
                lblConnectionStatus.Text = "Connecting";
                await CommunicationManager.Connection.StartAsync();
                UpdateConnectionState(CommunicationManager.Connection);
            }

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

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

            if (successful)
            {
                CommunicationManager.SessionData.SessionName = localContent.Content.TxtSession.Text;
                lblSessionName.Text = CommunicationManager.SessionData.SessionName;
                MenuConnectSync.Enabled = true;
                MenuConnectUpload.Enabled = true;
                localContent.Window.Close();
            }
        }

        private async void OnButtonInvitePlayerClicked(object sender, EventArgs e)
        {
            var localContent = ((TextButton)sender).GetParentContentInWindow<PlayerWindow>();// localWindow.Content as PlayerWindow;
            var isValid = localContent.Content.TxtCampaign.ValidateTextbox();
            if (!isValid)
            {
                return;
            }

            var successful = false;
            try
            {
                await CommunicationManager.Api.InvitePlayer(State.Instance.CampaignName, localContent.Content.TxtCampaign.Text);
            }
            catch (Exception ex)
            {
                SentrySdk.CaptureException(ex);
            }
            localContent.Window.Close();

        }

        private void OnBtnToolbarRoomClicked(object sender, EventArgs e)
        {
            State.Instance.InsertMode = InsertMode.NewRoom;
            ClearSelection();
            ((ImageTextButton)sender).Border = new SolidBrush(Color.Red);
            ((ImageTextButton)sender).BorderThickness = new Myra.Graphics2D.Thickness(2);

        }

        private void OnBtnToolbarLinClicked(object sender, EventArgs e)
        {
            State.Instance.InsertMode = InsertMode.NewLine;
            ClearSelection();
            ((ImageTextButton)sender).Border = new SolidBrush(Color.Red);
            ((ImageTextButton)sender).BorderThickness = new Myra.Graphics2D.Thickness(2);
        }

        private void OnBtnToolbarDeleteClicked(object sender, EventArgs e)
        {
            State.Instance.InsertMode = InsertMode.NewDelete;

            ClearSelection();
            ((ImageTextButton)sender).Border = new SolidBrush(Color.Red);
            ((ImageTextButton)sender).BorderThickness = new Myra.Graphics2D.Thickness(2);
        }

        private void OnMenuMapNew(object sender, EventArgs e)
        {
            if (sender is MenuItem && !((MenuItem)sender).Enabled)
            {
                return;
            }

            Window window = new()
            {
                Title = "New map"
            };

            var content = new MapWindow();
            //content.BtnNewCampaign.Text = "N";
            content.BtnNewCampaign.Click += OnButtonNewMapClicked;
            window.Content = content;

            window.ShowModal(Desktop);
            content.TxtCampaign.SetKeyboardFocus();
        }

        private async void OnButtonNewMapClicked(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 MapWindow;
            var isValid = localContent.TxtCampaign.ValidateTextbox();
            if (!isValid)
            {
                return;
            }

            var successful = false;
            try
            {
                await CommunicationManager.Api.NewSession(State.Instance.CampaignName, localContent.TxtCampaign.Text);

            }
            catch (Exception ex)
            {
                SentrySdk.CaptureException(ex);
            }

            localWindow.Close();
        }

        //TODO Refactor
        private void EditNote(Note note)
        {
            State.Instance.SelectedNote = new Note { X = note.X, Y = note.Y, Text = note.Text };
            Window window = new()
            {
                Title = $" Note on {note.X}:{note.Y}"
            };
            var noteWindow = new NoteWindow(CommunicationManager, window, note);

            window.Content = noteWindow;
            window.ShowModal(Desktop);
        }
    }
}