using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Logging;

namespace DiunaBI.UI.Shared.Services;

public class EntityChangeHubService : IAsyncDisposable
{
    private readonly string _hubUrl;
    private readonly ILogger<EntityChangeHubService> _logger;
    private readonly TokenProvider _tokenProvider;
    private HubConnection? _hubConnection;
    private bool _isInitialized;
    private readonly SemaphoreSlim _initializationLock = new SemaphoreSlim(1, 1);
    private static int _instanceCounter = 0;
    private readonly int _instanceId;

    // Events that components can subscribe to
    public event Action<string, string, string>? EntityChanged;

    public EntityChangeHubService(
        string apiBaseUrl,
        IServiceProvider serviceProvider,
        ILogger<EntityChangeHubService> logger,
        TokenProvider tokenProvider)
    {
        _instanceId = Interlocked.Increment(ref _instanceCounter);

        // Convert HTTP URL to SignalR hub URL
        var baseUrl = apiBaseUrl.TrimEnd('/');
        _hubUrl = baseUrl + "/hubs/entitychanges";

        _logger = logger;
        _tokenProvider = tokenProvider;
        _logger.LogInformation("🏗️ EntityChangeHubService instance #{InstanceId} created. Hub URL: {HubUrl}", _instanceId, _hubUrl);
        Console.WriteLine($"🏗️ EntityChangeHubService instance #{_instanceId} created. Hub URL: {_hubUrl}, _isInitialized = {_isInitialized}");
    }

    public async Task InitializeAsync()
    {
        _logger.LogInformation("🔍 Instance #{InstanceId} InitializeAsync called. _isInitialized = {IsInitialized}, _hubConnection null? {IsNull}", _instanceId, _isInitialized, _hubConnection == null);
        Console.WriteLine($"🔍 Instance #{_instanceId} InitializeAsync called. _isInitialized = {_isInitialized}, _hubConnection null? {_hubConnection == null}");

        if (_isInitialized)
        {
            _logger.LogInformation("⏭️ Instance #{InstanceId} SignalR already initialized, skipping", _instanceId);
            Console.WriteLine($"⏭️ Instance #{_instanceId} SignalR already initialized, skipping");
            return;
        }

        await _initializationLock.WaitAsync();
        try
        {
            // Double-check after acquiring lock
            if (_isInitialized)
            {
                Console.WriteLine($"⏭️ SignalR already initialized (after lock), skipping");
                return;
            }

            _logger.LogInformation("🔌 Initializing SignalR connection to {HubUrl}", _hubUrl);
            Console.WriteLine($"🔌 Initializing SignalR connection to {_hubUrl}");

            _hubConnection = new HubConnectionBuilder()
                .WithUrl(_hubUrl, options =>
                {
                    // Add JWT token to SignalR connection
                    if (!string.IsNullOrEmpty(_tokenProvider.Token))
                    {
                        options.AccessTokenProvider = () => Task.FromResult<string?>(_tokenProvider.Token);
                        _logger.LogInformation("✅ JWT token added to SignalR connection");
                        Console.WriteLine($"✅ JWT token added to SignalR connection");
                    }
                    else
                    {
                        _logger.LogWarning("⚠️ No JWT token available for SignalR connection");
                        Console.WriteLine($"⚠️ No JWT token available for SignalR connection");
                    }
                })
                .WithAutomaticReconnect()
                .Build();

            // Subscribe to EntityChanged messages
            _hubConnection.On<object>("EntityChanged", (data) =>
            {
                Console.WriteLine($"🔔 RAW SignalR message received at {DateTime.Now:HH:mm:ss.fff}");
                Console.WriteLine($"🔔 Data type: {data?.GetType().FullName}");

                try
                {
                    // Parse the anonymous object
                    var json = System.Text.Json.JsonSerializer.Serialize(data);
                    Console.WriteLine($"📨 Received SignalR message: {json}");

                    // Use case-insensitive deserialization (backend sends camelCase: module, id, operation)
                    var options = new System.Text.Json.JsonSerializerOptions
                    {
                        PropertyNameCaseInsensitive = true
                    };
                    var change = System.Text.Json.JsonSerializer.Deserialize<EntityChangeMessage>(json, options);

                    if (change != null)
                    {
                        _logger.LogInformation("📨 Received entity change: {Module} {Id} {Operation}",
                            change.Module, change.Id, change.Operation);
                        Console.WriteLine($"📨 Entity change: {change.Module} {change.Id} {change.Operation}");

                        // Notify all subscribers
                        Console.WriteLine($"🔔 Invoking EntityChanged event, subscribers: {EntityChanged?.GetInvocationList().Length ?? 0}");
                        EntityChanged?.Invoke(change.Module, change.Id, change.Operation);
                        Console.WriteLine($"🔔 EntityChanged event invoked successfully");
                    }
                    else
                    {
                        Console.WriteLine($"⚠️ Deserialized change is null");
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "❌ Error processing entity change message");
                    Console.WriteLine($"❌ Error processing message: {ex.Message}");
                    Console.WriteLine($"❌ Stack trace: {ex.StackTrace}");
                }
            });

            _hubConnection.Reconnecting += (error) =>
            {
                _logger.LogWarning("SignalR reconnecting: {Error}", error?.Message);
                Console.WriteLine($"⚠️ SignalR reconnecting: {error?.Message}");
                return Task.CompletedTask;
            };

            _hubConnection.Reconnected += (connectionId) =>
            {
                _logger.LogInformation("✅ SignalR reconnected: {ConnectionId}", connectionId);
                Console.WriteLine($"✅ SignalR reconnected: {connectionId}");
                return Task.CompletedTask;
            };

            _hubConnection.Closed += (error) =>
            {
                _logger.LogError(error, "❌ SignalR connection closed");
                Console.WriteLine($"❌ SignalR connection closed: {error?.Message}");
                return Task.CompletedTask;
            };

            await StartConnectionAsync();
            _isInitialized = true;
            _logger.LogInformation("✅ Instance #{InstanceId} _isInitialized set to true", _instanceId);
            Console.WriteLine($"✅ Instance #{_instanceId} _isInitialized set to true");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "❌ Instance #{InstanceId} Failed to initialize SignalR connection", _instanceId);
            Console.WriteLine($"❌ Instance #{_instanceId} Failed to initialize SignalR: {ex.Message}");
        }
        finally
        {
            _initializationLock.Release();
        }
    }

    private async Task StartConnectionAsync()
    {
        if (_hubConnection == null)
        {
            _logger.LogWarning("Hub connection is null, cannot start");
            return;
        }

        try
        {
            Console.WriteLine($"🔌 Starting SignalR connection...");
            await _hubConnection.StartAsync();
            _logger.LogInformation("✅ SignalR connected successfully");
            Console.WriteLine($"✅ SignalR connected successfully to {_hubUrl}");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "❌ Failed to start SignalR connection");
            Console.WriteLine($"❌ Failed to start SignalR: {ex.Message}\n{ex.StackTrace}");
        }
    }

    public async ValueTask DisposeAsync()
    {
        if (_hubConnection != null)
        {
            try
            {
                await _hubConnection.StopAsync();
                await _hubConnection.DisposeAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error disposing SignalR connection");
            }
        }

        _initializationLock?.Dispose();
    }
}

public class EntityChangeMessage
{
    public string Module { get; set; } = string.Empty;
    public string Id { get; set; } = string.Empty;
    public string Operation { get; set; } = string.Empty;
}
