// ============================================================================
// mb_clouseau - Panel Registry
// Uncovering clues with MusicBee Clouseau
//
// Tracks all panel registrations with full lifecycle
// ============================================================================

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using MusicBeePlugin.Clouseau.Core;

namespace MusicBeePlugin.Clouseau.Introspection
{
    /// <summary>
    /// Tracks all panel registrations, lifecycle events, and state changes.
    /// Provides comprehensive visibility into plugin panels.
    /// </summary>
    public class PanelRegistry : IDisposable
    {
        private readonly ConcurrentDictionary<IntPtr, PanelRegistration> _panels;
        private readonly ConcurrentQueue<PanelStateChange> _stateHistory;
        private const int MaxHistorySize = 500;
        private bool _disposed;

        /// <summary>
        /// Event raised when a panel is registered.
        /// </summary>
        public event EventHandler<PanelRegistration> PanelAdded;

        /// <summary>
        /// Event raised when a panel is removed.
        /// </summary>
        public event EventHandler<PanelRegistration> PanelRemoved;

        /// <summary>
        /// Event raised when panel state changes.
        /// </summary>
        public event EventHandler<PanelStateChange> PanelStateChanged;

        public PanelRegistry()
        {
            _panels = new ConcurrentDictionary<IntPtr, PanelRegistration>();
            _stateHistory = new ConcurrentQueue<PanelStateChange>();
        }

        /// <summary>
        /// Gets the count of registered panels.
        /// </summary>
        public int Count => _panels.Count;

        /// <summary>
        /// Registers a panel.
        /// </summary>
        public void RegisterPanel(Control panelControl, Plugin.PluginPanelDock dockLocation,
            string ownerPlugin = null, Control resultControl = null)
        {
            if (panelControl == null) return;

            var handle = panelControl.Handle;
            var reg = new PanelRegistration
            {
                PanelHandle = handle,
                PanelControl = panelControl,
                ResultControl = resultControl,
                DockLocation = dockLocation,
                OwnerPluginName = ownerPlugin ?? "Unknown",
                CreatedTime = DateTime.Now,
                InitialBounds = panelControl.Bounds,
                CurrentBounds = panelControl.Bounds,
                IsVisible = panelControl.Visible,
                IsActive = true,
                StateHistory = new List<PanelStateChange>()
            };

            if (_panels.TryAdd(handle, reg))
            {
                LogManager.Core.Debug($"Panel registered: Handle=0x{handle.ToInt64():X8}, " +
                    $"Dock={dockLocation}, Owner={ownerPlugin}");

                // Record initial state
                RecordStateChange(handle, PanelChangeType.Create, panelControl.Bounds, panelControl.Visible);

                OnPanelAdded(reg);
            }
        }

        /// <summary>
        /// Unregisters a panel.
        /// </summary>
        public void UnregisterPanel(Control panelControl)
        {
            if (panelControl == null) return;
            UnregisterPanel(panelControl.Handle);
        }

        /// <summary>
        /// Unregisters a panel by handle.
        /// </summary>
        public void UnregisterPanel(IntPtr handle)
        {
            if (_panels.TryRemove(handle, out var reg))
            {
                reg.RemovedTime = DateTime.Now;
                reg.IsActive = false;

                LogManager.Core.Debug($"Panel unregistered: Handle=0x{handle.ToInt64():X8}, " +
                    $"Lifetime={(reg.RemovedTime.Value - reg.CreatedTime).TotalSeconds:F1}s");

                RecordStateChange(handle, PanelChangeType.Remove, null, null);
                OnPanelRemoved(reg);
            }
        }

        /// <summary>
        /// Updates panel bounds.
        /// </summary>
        public void UpdateBounds(IntPtr handle, Rectangle bounds)
        {
            if (_panels.TryGetValue(handle, out var reg))
            {
                if (reg.CurrentBounds != bounds)
                {
                    reg.CurrentBounds = bounds;
                    RecordStateChange(handle, PanelChangeType.Resize, bounds, null);
                }
            }
        }

        /// <summary>
        /// Updates panel visibility.
        /// </summary>
        public void UpdateVisibility(IntPtr handle, bool visible)
        {
            if (_panels.TryGetValue(handle, out var reg))
            {
                if (reg.IsVisible != visible)
                {
                    reg.IsVisible = visible;
                    RecordStateChange(handle, PanelChangeType.Visibility, null, visible);
                }
            }
        }

        /// <summary>
        /// Gets all registered panels.
        /// </summary>
        public IReadOnlyList<PanelRegistration> GetAllPanels()
        {
            return _panels.Values.ToList();
        }

        /// <summary>
        /// Gets a panel by handle.
        /// </summary>
        public PanelRegistration GetPanelByHandle(IntPtr handle)
        {
            _panels.TryGetValue(handle, out var reg);
            return reg;
        }

        /// <summary>
        /// Gets panels for a specific dock location.
        /// </summary>
        public IReadOnlyList<PanelRegistration> GetPanelsByDock(Plugin.PluginPanelDock dock)
        {
            return _panels.Values.Where(p => p.DockLocation == dock).ToList();
        }

        /// <summary>
        /// Gets panels for a specific plugin.
        /// </summary>
        public IReadOnlyList<PanelRegistration> GetPanelsByPlugin(string pluginName)
        {
            return _panels.Values
                .Where(p => p.OwnerPluginName.Equals(pluginName, StringComparison.OrdinalIgnoreCase))
                .ToList();
        }

        /// <summary>
        /// Gets recent state changes.
        /// </summary>
        public IReadOnlyList<PanelStateChange> GetRecentStateChanges(int count = 50)
        {
            var all = _stateHistory.ToArray();
            return all.Skip(Math.Max(0, all.Length - count)).ToList();
        }

        /// <summary>
        /// Gets a summary of panel registry state.
        /// </summary>
        public PanelRegistrySummary GetSummary()
        {
            var panels = _panels.Values.ToList();
            return new PanelRegistrySummary
            {
                TotalPanels = panels.Count,
                ActivePanels = panels.Count(p => p.IsActive),
                VisiblePanels = panels.Count(p => p.IsVisible),
                PanelsByDock = panels.GroupBy(p => p.DockLocation)
                    .ToDictionary(g => g.Key, g => g.Count()),
                PanelsByPlugin = panels.GroupBy(p => p.OwnerPluginName)
                    .ToDictionary(g => g.Key, g => g.Count()),
                StateChangeCount = _stateHistory.Count
            };
        }

        private void RecordStateChange(IntPtr handle, PanelChangeType changeType,
            Rectangle? bounds, bool? visibility)
        {
            var change = new PanelStateChange
            {
                Timestamp = DateTime.Now,
                PanelHandle = handle,
                ChangeType = changeType,
                Bounds = bounds,
                Visibility = visibility
            };

            _stateHistory.Enqueue(change);
            while (_stateHistory.Count > MaxHistorySize)
            {
                _stateHistory.TryDequeue(out _);
            }

            // Also add to panel's own history
            if (_panels.TryGetValue(handle, out var reg))
            {
                reg.StateHistory.Add(change);
            }

            OnPanelStateChanged(change);
        }

        protected virtual void OnPanelAdded(PanelRegistration reg)
            => PanelAdded?.Invoke(this, reg);

        protected virtual void OnPanelRemoved(PanelRegistration reg)
            => PanelRemoved?.Invoke(this, reg);

        protected virtual void OnPanelStateChanged(PanelStateChange change)
            => PanelStateChanged?.Invoke(this, change);

        public void Dispose()
        {
            if (!_disposed)
            {
                _panels.Clear();
                _disposed = true;
            }
        }
    }

    /// <summary>
    /// Represents a registered panel.
    /// </summary>
    public class PanelRegistration
    {
        public IntPtr PanelHandle { get; set; }
        public Control PanelControl { get; set; }
        public Control ResultControl { get; set; }
        public Plugin.PluginPanelDock DockLocation { get; set; }
        public string OwnerPluginName { get; set; }
        public DateTime CreatedTime { get; set; }
        public DateTime? RemovedTime { get; set; }
        public Rectangle InitialBounds { get; set; }
        public Rectangle CurrentBounds { get; set; }
        public bool IsVisible { get; set; }
        public bool IsActive { get; set; }
        public List<PanelStateChange> StateHistory { get; set; }

        public TimeSpan? Lifetime => RemovedTime.HasValue
            ? RemovedTime.Value - CreatedTime
            : (DateTime.Now - CreatedTime);
    }

    /// <summary>
    /// Types of panel state changes.
    /// </summary>
    public enum PanelChangeType
    {
        Create,
        Resize,
        Visibility,
        Remove
    }

    /// <summary>
    /// Represents a panel state change.
    /// </summary>
    public class PanelStateChange
    {
        public DateTime Timestamp { get; set; }
        public IntPtr PanelHandle { get; set; }
        public PanelChangeType ChangeType { get; set; }
        public Rectangle? Bounds { get; set; }
        public bool? Visibility { get; set; }
    }

    /// <summary>
    /// Summary of panel registry state.
    /// </summary>
    public class PanelRegistrySummary
    {
        public int TotalPanels { get; set; }
        public int ActivePanels { get; set; }
        public int VisiblePanels { get; set; }
        public Dictionary<Plugin.PluginPanelDock, int> PanelsByDock { get; set; }
        public Dictionary<string, int> PanelsByPlugin { get; set; }
        public int StateChangeCount { get; set; }
    }
}
