using DbController;
using DbController.SqlServer;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.JSInterop;
using Tabletop.Core.Constants;
using Tabletop.Core.Models;
using Tabletop.Core.Services;

namespace Tabletop.Pages.Games
{
    public partial class GameLobby
    {
        [Parameter]
        public string GUID { get; set; } = string.Empty;

        [Inject] public required IJSRuntime JSRuntime { get; set; }

        private User? _loggedInUser;
        private HubConnection? _hubConnection;

        protected override async Task OnInitializedAsync()
        {
            // Prüfe, ob ein Reload durchgeführt wurde, indem wir sessionStorage verwenden
            string? existingConnection = await JSRuntime.InvokeAsync<string>("sessionStorage.getItem", "connectionActive");
            string baseUri = navigationManager.BaseUri;
            string hubUrl = $"{baseUri}Lobbyhub";

            _loggedInUser = await authService.GetUserAsync();

            

            if (!string.IsNullOrEmpty(existingConnection) && existingConnection == GUID)
            {
                // Verbindung wiederherstellen
                Console.WriteLine("Restoring existing connection...");
                _hubConnection = new HubConnectionBuilder()
                    .WithUrl(hubUrl, (opts) =>
                    {
                        opts.HttpMessageHandlerFactory = (message) =>
                        {
                            if (message is HttpClientHandler clientHandler)
                                clientHandler.ServerCertificateCustomValidationCallback +=
                                    (sender, certificate, chain, sslPolicyErrors) => { return true; };
                            return message;
                        };
                    })
                    .Build();

                // SignalR-Verbindung wieder starten
                await _hubConnection.StartAsync();
            }
            else
            {
                // Normale Initialisierung
                if (AppdataService.Games.TryGetValue(GUID, out Game? value))
                {
                    // SignalR-Verbindung aufbauen
                    _hubConnection = new HubConnectionBuilder()
                        .WithUrl(hubUrl, (opts) =>
                        {
                            opts.HttpMessageHandlerFactory = (message) =>
                            {
                                if (message is HttpClientHandler clientHandler)
                                    clientHandler.ServerCertificateCustomValidationCallback +=
                                        (sender, certificate, chain, sslPolicyErrors) => { return true; };
                                return message;
                            };
                        })
                        .Build();

                    // Event-Handler registrieren
                    _hubConnection.On("PlayerJoined", async () =>
                    {
                        await InvokeAsync(StateHasChanged);
                    });

                    _hubConnection.On("PlayerUpdated", async () =>
                    {
                        await InvokeAsync(StateHasChanged);
                    });

                    _hubConnection.On("PlayerDisconnected", async () =>
                    {
                        await InvokeAsync(StateHasChanged);
                    });

                    _hubConnection.On("GameUpdated", async () =>
                    {
                        await InvokeAsync(StateHasChanged);
                    });

                    _hubConnection.On("GameStarted", () =>
                    {
                        navigationManager.NavigateTo($"/Games/{AppdataService.Games[GUID].GameId}");
                    });

                    _hubConnection.On("PlayerAlreadyInLobby", () =>
                    {
                        navigationManager.NavigateTo("/Games");
                    });

                    _hubConnection.On("LobbyFull", () =>
                    {
                        navigationManager.NavigateTo("/Games");
                    });

                    _hubConnection.On("GameClosed", () =>
                    {
                        navigationManager.NavigateTo("/Games");
                    });

                    try
                    {
                        await _hubConnection.StartAsync();
                        Console.WriteLine("Connection started successfully.");
                        await JoinLobbyAsync();

                        // Speichere die Verbindung im sessionStorage
                        await JSRuntime.InvokeVoidAsync("sessionStorage.setItem", "connectionActive", GUID);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Connection failed: {ex.Message}");
                    }
                }
            }
        }

        private async Task JoinLobbyAsync()
        {
            int retries = 0;
            while (_hubConnection?.State != HubConnectionState.Connected && retries < 5)
            {
                retries++;
                Console.WriteLine("Waiting for the connection to become active...");
                await Task.Delay(200);
            }

            if (_hubConnection?.State == HubConnectionState.Connected)
            {
                await _hubConnection.SendAsync("JoinLobby", _loggedInUser?.UserId, 1, GUID);
            }
            else
            {
                Console.WriteLine("The hub connection is not active after retries.");
            }
        }

        private async Task UpdatePlayerAsync(Player player)
        {
            await Task.Delay(200);
            if (_hubConnection?.State == HubConnectionState.Connected)
            {
                await _hubConnection.SendAsync("UpdatePlayer", _loggedInUser?.UserId, player.Team, player.FractionId, player.IsReady, GUID);
            }
        }

        private async Task UpdateGameAsync()
        {
            await Task.Delay(200);
            if (_hubConnection?.State == HubConnectionState.Connected)
            {
                await _hubConnection.SendAsync("UpdateGame", GUID);
            }
        }

        public Task<bool> IsConnected => Task.FromResult(_hubConnection?.State == HubConnectionState.Connected);

        public async ValueTask DisposeAsync()
        {
            if (_hubConnection is not null)
            {
                bool isReloading = false;

                try
                {
                    // Überprüfe, ob die Seite neu geladen wird
                    isReloading = await JSRuntime.InvokeAsync<bool>("isPageReloading");
                }
                catch (JSException ex)
                {
                    Console.WriteLine($"JavaScript function 'isPageReloading' is not available: {ex.Message}");
                }

                // Wenn die Seite nicht neu geladen wird, trenne die Verbindung und lösche das Spiel, falls erforderlich
                if (!isReloading)
                {
                    Console.WriteLine("Disposing hub connection...");

                    // Stoppe die Verbindung, falls sie noch aktiv ist
                    if (_hubConnection.State == HubConnectionState.Connected)
                    {
                        await _hubConnection.StopAsync();
                    }

                    // Dispose aufrufen, um Ressourcen freizugeben
                    await _hubConnection.DisposeAsync();

                    // Setze den HubConnection auf null, um zu verhindern, dass später darauf zugegriffen wird
                    _hubConnection = null;

                    // Prüfe, ob das Spiel existiert und ob der Benutzer der Host ist
                    if (AppdataService.Games.TryGetValue(GUID, out Game? game))
                    {
                        if (game.UserId == _loggedInUser?.UserId) // Wenn der Host das Spiel verlässt
                        {
                            Console.WriteLine("Host has left. Deleting the game...");
                            AppdataService.Games.Remove(GUID);

                            // Sende SignalR-Benachrichtigung, um andere Spieler zu informieren
                            // Nur wenn die Verbindung noch aktiv ist
                            if (_hubConnection?.State == HubConnectionState.Connected)
                            {
                                await _hubConnection.SendAsync("GameClosed", GUID);
                            }
                        }
                    }
                }

                // Entferne den connectionActive-Wert aus dem sessionStorage, wenn die Verbindung getrennt wird
                try
                {
                    await JSRuntime.InvokeVoidAsync("sessionStorage.removeItem", "connectionActive");
                }
                catch (JSException jsEx)
                {
                    Console.WriteLine($"Error removing item from sessionStorage: {jsEx.Message}");
                }
            }
        }

        public async Task ToggleReadyAsync(Player player)
        {
            if (player.IsReady)
            {
                player.IsReady = false;
            }
            else
            {
                player.IsReady = true;
            }
            await UpdatePlayerAsync(player);
        }

        private async Task CycleColorAsync(Player player)
        {
            // Hole alle derzeit benutzten Farben (außer die eigene)
            var usedColors = AppdataService.Games[GUID].Players
                .Where(p => p.UserId != player.UserId)
                .Select(p => p.Color)
                .ToHashSet();

            var colors = PlayerColors.Colors;

            // Finde die aktuelle Farbe in der Liste
            var currentIndex = colors.IndexOf(player.Color);

            // Starte bei der nächsten Farbe und suche eine, die noch nicht benutzt ist
            for (int i = 1; i <= colors.Count; i++)
            {
                var nextIndex = (currentIndex + i) % colors.Count;
                var nextColor = colors[nextIndex];
                if (!usedColors.Contains(nextColor))
                {
                    player.Color = nextColor;
                    await UpdatePlayerAsync(player);
                    break;
                }
            }
        }

        protected async Task StartGameAsync()
        {
            if (!AppdataService.Games[GUID].Players.All(Player => Player.IsReady) || _hubConnection is null)
            {
                return;
            }

            using IDbController dbController = new SqlController(AppdataService.ConnectionString);
            await dbController.StartTransactionAsync();
            try
            {
                await gameService.CreateAsync(AppdataService.Games[GUID], dbController);

                await dbController.CommitChangesAsync();
                AppdataService.UpdateRecord(AppdataService.Games[GUID]);

                await _hubConnection.SendAsync("GameStartAsync", GUID);
            }
            catch (Exception)
            {
                await dbController.RollbackChangesAsync();
                throw;
            }
        }
    }
}