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

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

        private TinyMessengerHub Messenger { get; }

        private GameWindow Window { get; }

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

            Messenger.Subscribe<LoginSuccesfulMessage>(OnLoginSuccesfulMessage);
            Messenger.Subscribe<SignalrConnectionUpdateMessage>(OnSignalrConnectionUpdateMessage);
            Messenger.Subscribe<MapOpenedMessage>(OnMapOpenedMessage);
            Messenger.Subscribe<CenterOnTileMessage>(OnCenterOnTileMessage);
            Messenger.Subscribe<CampaignSelectedMessage>(OnCampaignSelectedMessage);
            Messenger.Subscribe<ErrorMessage>(OnErrorMessage);


            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;


        }

        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);
        }

        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;
        }

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

        private void OnBtnToolbarDeleteClicked(object sender, EventArgs e)
        {
            Messenger.Publish(new ErrorMessage(this, "test"));
            State.Instance.InsertMode = InsertMode.NewDelete;

            ClearSelection();
            ((ImageTextButton)sender).Border = new SolidBrush(Color.Red);
            ((ImageTextButton)sender).BorderThickness = new 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 Thickness(2);
        }

        //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;
        //        lblMap.Text = CommunicationManager.SessionData.SessionName;
        //        MenuConnectSync.Enabled = true;
        //        MenuConnectUpload.Enabled = true;
        //        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 Thickness(2);
        }

        private void OnCampaignSelectedMessage(CampaignSelectedMessage obj)
        {
            lblCampaign.Text = State.Instance.CampaignName;

            MenuMapNew.Enabled = true;
            MenuMapOpen.Enabled = true;
            MenuCampaignPlayers.Enabled = true;
        }

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

        private void OnErrorMessage(ErrorMessage obj)
        {
            new ErrorWindow(obj.Message).Toast(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 OnLoginSuccesfulMessage(LoginSuccesfulMessage obj)
        {
            //MenuConnectNew.Enabled = true;
            //MenuConnectJoin.Enabled = true;
            MenuCampaignOpen.Enabled = true;
            MenuCampaingNew.Enabled = true;

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

        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 OnMapOpenedMessage(MapOpenedMessage obj)
        {
            lblMap.Text = obj.MapName;
            State.Instance.MapId = obj.MapId;
            State.Instance.MapName = obj.MapName;
            CommunicationManager.SessionData.SessionName = obj.MapName;
            CommunicationManager.SessionData.SessionId = obj.MapId;

            MenuConnectSync.Enabled = true;
            MenuConnectUpload.Enabled = true;
            CommunicationManager.SessionData.MapEntityAdded -= OnMapEntityAdded;
            CommunicationManager.SessionData.MapEntityDeleted -= OnMapEntityDeleted;
            CommunicationManager.SessionData.MapEntityAdded += OnMapEntityAdded;
            CommunicationManager.SessionData.MapEntityDeleted += OnMapEntityDeleted;
            var serverMap = await CommunicationManager.Api.GetMap(State.Instance.CampaignId, State.Instance.MapId);
            if (CommunicationManager.Connection.State != HubConnectionState.Connected)
            {
                await CommunicationManager.Connection.StartAsync();
                UpdateConnectionState(CommunicationManager.Connection);
            }

            var result = await CommunicationManager.Connection?.InvokeAsync<bool>("JoinSession", State.Instance.MapId);

            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 void OnMenuCampaignNew(object sender, EventArgs e)
        {
            if (sender is MenuItem { Enabled: false }) return;

            new CampaignWindow(CommunicationManager, Messenger).ShowInModalWindow(Desktop, "New campaign");
            ;
        }

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

            var content = new CampaignList(CommunicationManager, Messenger);
            if (await content.LoadCampaigns())
            {
                content.ShowInModalWindow(Desktop, "Campaigns");
            }
        }

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

            var content = new PlayerList(CommunicationManager);
            if (await content.LoadPlayers())
            {
                content.ShowInModalWindow(Desktop, "Players");
            }
        }

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

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

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

            var serverMap = await CommunicationManager.Api.GetMap(State.Instance.CampaignId, State.Instance.MapId);
            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, State.Instance.MapId);
        }

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

            dialog.Closed += (s, a) =>
            {
                if (!dialog.Result) return;
                using var 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 OnMenuFileSaveSelected(object sender, EventArgs e)
        {
            FileDialog dialog = new(FileDialogMode.SaveFile)
            {
                Filter = "*.map"
            };

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

                using var file = File.CreateText(dialog.FilePath);
                JsonSerializer serializer = new();
                serializer.Serialize(file, CommunicationManager.SessionData);
            };

            dialog.ShowModal(Desktop);
        }

        private void OnMenuMapNew(object sender, EventArgs e)
        {
            if (sender is MenuItem { Enabled: false }) return;

            new MapWindow(CommunicationManager, Messenger).ShowInModalWindow(Desktop, "New map");
        }

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

            var content = new MapList(CommunicationManager, Messenger);
            if (await content.LoadMaps())
            {
                content.ShowInModalWindow(Desktop, "Maps");
            }
        }

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

        private void OnMenuViewNotesSelected(object sender, EventArgs e)
        {
            new NoteList(CommunicationManager, Messenger).ShowInModalWindow(Desktop, "Notes");
        }

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

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


        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;
            }
        }
    }
}