using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;

namespace DiunaBI.Infrastructure.Interceptors;

public class EntityChangeInterceptor : SaveChangesInterceptor
{
    private readonly object? _hubContext;
    private readonly ILogger<EntityChangeInterceptor>? _logger;
    private readonly List<(string Module, string Id, string Operation)> _pendingChanges = new();

    public EntityChangeInterceptor(IServiceProvider serviceProvider)
    {
        _logger = serviceProvider.GetService(typeof(ILogger<EntityChangeInterceptor>)) as ILogger<EntityChangeInterceptor>;

        // Try to get hub context - it may not be registered in some scenarios (e.g., migrations)
        try
        {
            var hubType = Type.GetType("DiunaBI.API.Hubs.EntityChangeHub, DiunaBI.API");
            if (hubType != null)
            {
                var hubContextType = typeof(IHubContext<>).MakeGenericType(hubType);
                _hubContext = serviceProvider.GetService(hubContextType);

                if (_hubContext != null)
                {
                    _logger?.LogInformation("✅ EntityChangeInterceptor: Hub context initialized");
                    Console.WriteLine("✅ EntityChangeInterceptor: Hub context initialized");
                }
                else
                {
                    _logger?.LogWarning("⚠️ EntityChangeInterceptor: Hub context is null");
                    Console.WriteLine("⚠️ EntityChangeInterceptor: Hub context is null");
                }
            }
            else
            {
                _logger?.LogWarning("⚠️ EntityChangeInterceptor: Hub type not found");
                Console.WriteLine("⚠️ EntityChangeInterceptor: Hub type not found");
            }
        }
        catch (Exception ex)
        {
            _logger?.LogError(ex, "❌ EntityChangeInterceptor: Failed to initialize hub context");
            Console.WriteLine($"❌ EntityChangeInterceptor: Failed to initialize hub context: {ex.Message}");
            _hubContext = null;
        }
    }

    public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
        DbContextEventData eventData,
        InterceptionResult<int> result,
        CancellationToken cancellationToken = default)
    {
        _pendingChanges.Clear();

        Console.WriteLine($"🔍 EntityChangeInterceptor.SavingChangesAsync called. HubContext null? {_hubContext == null}, Context null? {eventData.Context == null}");

        if (_hubContext != null && eventData.Context != null)
        {
            // Capture changes BEFORE save
            var entries = eventData.Context.ChangeTracker.Entries().ToList();
            Console.WriteLine($"🔍 Found {entries.Count} total entries in ChangeTracker");

            foreach (var entry in entries)
            {
                Console.WriteLine($"🔍 Entry: {entry.Metadata.ClrType.Name}, State: {entry.State}");

                if (entry.State == EntityState.Added ||
                    entry.State == EntityState.Modified ||
                    entry.State == EntityState.Deleted)
                {
                    var module = entry.Metadata.GetTableName() ?? entry.Metadata.ClrType.Name;
                    var id = GetEntityId(entry);
                    var operation = entry.State switch
                    {
                        EntityState.Added => "created",
                        EntityState.Modified => "updated",
                        EntityState.Deleted => "deleted",
                        _ => "unknown"
                    };

                    Console.WriteLine($"🔍 Detected change: {module} {id} {operation}");

                    if (id != null)
                    {
                        _pendingChanges.Add((module, id, operation));
                        Console.WriteLine($"✅ Added to pending changes: {module} {id} {operation}");
                    }
                    else
                    {
                        Console.WriteLine($"⚠️ Skipped (id is null): {module} {operation}");
                    }
                }
            }

            Console.WriteLine($"🔍 Total pending changes: {_pendingChanges.Count}");
        }

        return base.SavingChangesAsync(eventData, result, cancellationToken);
    }

    public override async ValueTask<int> SavedChangesAsync(
        SaveChangesCompletedEventData eventData,
        int result,
        CancellationToken cancellationToken = default)
    {
        // Broadcast changes AFTER successful save
        if (_hubContext != null && result > 0 && _pendingChanges.Any())
        {
            _logger?.LogInformation("📤 Broadcasting {Count} entity changes via SignalR", _pendingChanges.Count);
            Console.WriteLine($"📤 Broadcasting {_pendingChanges.Count} entity changes via SignalR");

            foreach (var (module, id, operation) in _pendingChanges)
            {
                try
                {
                    Console.WriteLine($"📤 Broadcasting: {module} {id} {operation}");

                    // Use reflection to call hub methods since we can't reference the API project
                    var clientsProperty = _hubContext.GetType().GetProperty("Clients");
                    Console.WriteLine($"   🔍 Clients property: {clientsProperty != null}");

                    if (clientsProperty != null)
                    {
                        var clients = clientsProperty.GetValue(_hubContext);
                        Console.WriteLine($"   🔍 Clients value: {clients != null}, Type: {clients?.GetType().Name}");

                        if (clients != null)
                        {
                            var allProperty = clients.GetType().GetProperty("All");
                            Console.WriteLine($"   🔍 All property: {allProperty != null}");

                            if (allProperty != null)
                            {
                                var allClients = allProperty.GetValue(clients);
                                Console.WriteLine($"   🔍 AllClients value: {allClients != null}, Type: {allClients?.GetType().Name}");

                                if (allClients != null)
                                {
                                    // SendAsync is an extension method, so we need to find it differently
                                    // Look for the IClientProxy interface which has SendCoreAsync
                                    var sendCoreAsyncMethod = allClients.GetType().GetMethod("SendCoreAsync");
                                    Console.WriteLine($"   🔍 SendCoreAsync method found: {sendCoreAsyncMethod != null}");

                                    if (sendCoreAsyncMethod != null)
                                    {
                                        // SendCoreAsync takes (string method, object?[] args, CancellationToken cancellationToken)
                                        var task = sendCoreAsyncMethod.Invoke(allClients, new object[]
                                        {
                                            "EntityChanged",
                                            new object[] { new { module, id, operation } },
                                            cancellationToken
                                        }) as Task;

                                        Console.WriteLine($"   🔍 Task created: {task != null}");

                                        if (task != null)
                                        {
                                            await task;
                                            Console.WriteLine($"✅ Broadcast successful: {module} {id} {operation}");
                                        }
                                        else
                                        {
                                            Console.WriteLine($"❌ Task is null after invoke");
                                        }
                                    }
                                    else
                                    {
                                        Console.WriteLine($"❌ SendCoreAsync method not found");
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger?.LogError(ex, "❌ Failed to broadcast entity change");
                    Console.WriteLine($"❌ Failed to broadcast: {ex.Message}");
                    Console.WriteLine($"❌ Stack trace: {ex.StackTrace}");
                }
            }
        }

        _pendingChanges.Clear();
        return await base.SavedChangesAsync(eventData, result, cancellationToken);
    }

    private static string? GetEntityId(Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry entry)
    {
        var keyProperty = entry.Metadata.FindPrimaryKey()?.Properties.FirstOrDefault();
        if (keyProperty == null)
            return null;

        var value = entry.Property(keyProperty.Name).CurrentValue;
        return value?.ToString();
    }
}
