using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using MusicBeePlugin.Clouseau.Core;
using MusicBeePlugin.Clouseau.Introspection;
using MusicBeePlugin.Clouseau.Logging;
using MusicBeePlugin.Clouseau.Metrics;
using MusicBeePlugin.Clouseau.UI;

internal static class NativeMethods
{
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
}

/// <summary>
/// Wrapper to use a native window handle as an IWin32Window owner.
/// </summary>
internal class NativeWindowWrapper : IWin32Window
{
    public IntPtr Handle { get; }
    public NativeWindowWrapper(IntPtr handle) => Handle = handle;
}

namespace MusicBeePlugin
{
    public partial class Plugin
    {
        // Static API reference for other components
        public static MusicBeeApiInterface MbApiInterface { get; private set; }
        public static string DataPath { get; private set; }
        public static ApiInterceptor ApiInterceptor { get; private set; }

        private PluginInfo _about = new PluginInfo();
        private ClouseauSettings _settings;
        private StateManager _stateManager;
        private EventLogger _eventLogger;
        private ApiInterceptor _apiInterceptor;
        private MetricsCollector _metricsCollector;
        private bool _initialized;

        // UI Components
        private LogViewerPanelControl _logViewerPanelControl;
        private SettingsDialog _activeSettingsDialog;

        public PluginInfo Initialise(IntPtr apiInterfacePtr)
        {
            // IMPORTANT: MusicBeeApiInterface is a STRUCT - must init local copy first
            // then assign, otherwise property getter returns a copy that gets discarded
            var api = new MusicBeeApiInterface();
            api.Initialise(apiInterfacePtr);
            MbApiInterface = api;

            _about.PluginInfoVersion = PluginInfoVersion;
            _about.Name = "Clouseau";
            _about.Description = "Trace/debug utility for plugin developers";
            _about.Author = "Halrad";
            _about.TargetApplication = "Clouseau";
            _about.Type = PluginType.General;

            var version = Assembly.GetExecutingAssembly().GetName().Version;
            _about.VersionMajor = (short)version.Major;
            _about.VersionMinor = (short)version.Minor;
            _about.Revision = (short)version.Build;
            _about.MinInterfaceVersion = MinInterfaceVersion;
            _about.MinApiRevision = MinApiRevision;

            // Subscribe to ALL notification flags
            _about.ReceiveNotifications = ReceiveNotificationFlags.PlayerEvents
                                        | ReceiveNotificationFlags.DataStreamEvents
                                        | ReceiveNotificationFlags.TagEvents
                                        | ReceiveNotificationFlags.DownloadEvents;

            _about.ConfigurationPanelHeight = 70;

            // Add Clouseau submenu under Tools (like Chromecast plugin)
            // Use 'as' pattern to avoid InvalidCastException if API returns unexpected type
            if (MbApiInterface.MB_AddMenuItem("mnuTools/Clouseau", null, null) is ToolStripMenuItem mainMenu)
            {
                mainMenu.DropDown?.Items.Add("Dashboard", null, OnDashboardClick);
                mainMenu.DropDown?.Items.Add("Settings...", null, OnSettingsClick);
                mainMenu.DropDown?.Items.Add("Live Events", null, OnLiveEventsClick);
            }

            return _about;
        }

        private void InitializePlugin()
        {
            if (_initialized) return;

            try
            {
                // Set up data path first
                DataPath = Path.Combine(MbApiInterface.Setting_GetPersistentStoragePath(), "mb_clouseau");
                if (!Directory.Exists(DataPath))
                    Directory.CreateDirectory(DataPath);

                // Initialize logging
                LogManager.Initialize(DataPath);
                LogManager.Core.Info("Clouseau plugin initializing...");

                // Load settings
                _settings = ClouseauSettings.Load(DataPath);
                LogManager.Core.Info($"Settings loaded from {DataPath}");

                // Initialize state manager
                _stateManager = new StateManager(DataPath);
                _stateManager.StartSession();
                LogManager.Core.Info($"Session started at {_stateManager.SessionStartTime}");

                // Initialize event logger
                _eventLogger = new EventLogger(MbApiInterface);
                LogManager.Core.Info("EventLogger initialized");

                // Initialize metrics collector
                _metricsCollector = new MetricsCollector();
                _metricsCollector.Start();
                LogManager.Core.Info("MetricsCollector started");

                // Initialize API interceptor (Phase 2 feature)
                bool apiInterceptionEnabled = _settings?.Performance?.TrackApiCalls ?? true;
                int warnThreshold = _settings?.Performance?.WarnThresholdMs ?? 100;
                int errorThreshold = _settings?.Performance?.ErrorThresholdMs ?? 500;

                _apiInterceptor = new ApiInterceptor(apiInterceptionEnabled, warnThreshold, errorThreshold);
                ApiInterceptor = _apiInterceptor;

                // Use named handlers for proper cleanup in Close()
                _apiInterceptor.SlowCallDetected += OnSlowCallDetected;
                _apiInterceptor.AnomalyDetected += OnAnomalyDetected;

                var apiInterface = MbApiInterface;
                if (_apiInterceptor.WrapApiDelegates(ref apiInterface))
                {
                    MbApiInterface = apiInterface;
                    LogManager.Core.Info($"API interception enabled");
                }

                // Mark as initialized only on success
                _initialized = true;
                LogManager.Core.Info("Clouseau initialized successfully");
            }
            catch (Exception ex)
            {
                // Show error to user and allow retry
                MessageBox.Show($"Clouseau init failed:\n{ex.Message}", "Clouseau Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                System.Diagnostics.Debug.WriteLine($"Clouseau initialization failed: {ex}");
            }
        }

        public bool Configure(IntPtr panelHandle)
        {
            if (panelHandle != IntPtr.Zero)
            {
                Panel configPanel = (Panel)Panel.FromHandle(panelHandle);

                Color backColor = Color.FromArgb(MbApiInterface.Setting_GetSkinElementColour(
                    SkinElement.SkinInputControl, ElementState.ElementStateDefault, ElementComponent.ComponentBackground));
                Color foreColor = Color.FromArgb(MbApiInterface.Setting_GetSkinElementColour(
                    SkinElement.SkinInputPanelLabel, ElementState.ElementStateDefault, ElementComponent.ComponentForeground));
                Color borderColor = Color.FromArgb(MbApiInterface.Setting_GetSkinElementColour(
                    SkinElement.SkinInputControl, ElementState.ElementStateDefault, ElementComponent.ComponentBorder));

                var btnDashboard = new Button
                {
                    Text = "Dashboard",
                    Location = new Point(0, 0),
                    Size = new Size(100, 40),
                    FlatStyle = FlatStyle.Flat,
                    BackColor = backColor,
                    ForeColor = foreColor
                };
                btnDashboard.FlatAppearance.BorderColor = borderColor;
                btnDashboard.FlatAppearance.BorderSize = 1;
                btnDashboard.Click += OnDashboardClick;

                var btnSettings = new Button
                {
                    Text = "Settings...",
                    Location = new Point(105, 0),
                    Size = new Size(100, 40),
                    FlatStyle = FlatStyle.Flat,
                    BackColor = backColor,
                    ForeColor = foreColor
                };
                btnSettings.FlatAppearance.BorderColor = borderColor;
                btnSettings.FlatAppearance.BorderSize = 1;
                btnSettings.Click += OnSettingsClick;

                var lblStatus = new Label
                {
                    Text = $"Events: {_stateManager?.TotalEventCount ?? 0} | Session: {_stateManager?.SessionStartTime:HH:mm:ss}",
                    Location = new Point(0, 50),
                    AutoSize = true,
                    ForeColor = foreColor
                };

                configPanel.Controls.AddRange(new Control[] { btnDashboard, btnSettings, lblStatus });
            }
            return false;
        }

        /// <summary>
        /// Opens the Settings dialog (non-modal).
        /// </summary>
        private void OnSettingsClick(object sender, EventArgs e)
        {
            try
            {
                if (!_initialized) InitializePlugin();
                if (string.IsNullOrEmpty(DataPath))
                {
                    MessageBox.Show("Plugin not fully initialized yet.", "Clouseau", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }

                // Dispose any existing dialog before creating new one
                if (_activeSettingsDialog != null && !_activeSettingsDialog.IsDisposed)
                {
                    _activeSettingsDialog.Close();
                    _activeSettingsDialog.Dispose();
                }

                _activeSettingsDialog = new SettingsDialog(_settings, DataPath);
                _activeSettingsDialog.FormClosed += OnSettingsDialogClosed;

                // Center over MusicBee window
                var mbHandle = MbApiInterface.MB_GetWindowHandle();
                if (mbHandle != IntPtr.Zero)
                {
                    // Manually center over MusicBee (not a managed control)
                    _activeSettingsDialog.StartPosition = FormStartPosition.Manual;
                    _activeSettingsDialog.Load += OnSettingsDialogLoad;
                    _activeSettingsDialog.Show(new NativeWindowWrapper(mbHandle));
                }
                else
                {
                    _activeSettingsDialog.StartPosition = FormStartPosition.CenterScreen;
                    _activeSettingsDialog.Show();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Failed to open settings: {ex.Message}", "Clouseau Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        public void Close(PluginCloseReason reason)
        {
            LogManager.Core.Info($"Clouseau closing. Reason: {reason}");

            // Log API interceptor statistics before shutdown
            if (_apiInterceptor != null && _apiInterceptor.IsIntercepting)
            {
                LogManager.Performance.Info(_apiInterceptor.GetStatisticsSummary());
            }

            // Unsubscribe event handlers to prevent leaks
            if (_apiInterceptor != null)
            {
                _apiInterceptor.SlowCallDetected -= OnSlowCallDetected;
                _apiInterceptor.AnomalyDetected -= OnAnomalyDetected;
            }

            // Dispose active settings dialog if open
            if (_activeSettingsDialog != null && !_activeSettingsDialog.IsDisposed)
            {
                _activeSettingsDialog.Close();
                _activeSettingsDialog.Dispose();
                _activeSettingsDialog = null;
            }

            // Stop and dispose metrics collector
            _metricsCollector?.Stop();
            _metricsCollector?.Dispose();

            // Dispose event logger
            _eventLogger?.Dispose();

            // Save state
            _stateManager?.EndSession();
            _settings?.Save(DataPath);

            // Shutdown logging
            LogManager.Shutdown();
        }

        #region Named Event Handlers (for proper cleanup)

        private void OnSlowCallDetected(object sender, SlowApiCallEventArgs args)
        {
            LogManager.Performance.Warn($"Slow API call: {args.MethodName} ({args.DurationMs}ms)");
        }

        private void OnAnomalyDetected(object sender, ApiAnomalyEventArgs args)
        {
            LogManager.Performance.Warn($"API anomaly: {args.AnomalyType} - {args.Description}");
        }

        private void OnSettingsDialogClosed(object sender, FormClosedEventArgs args)
        {
            if (_activeSettingsDialog != null)
            {
                _settings = _activeSettingsDialog.Settings;
                LogManager.Core.Info("Settings dialog closed");
            }
        }

        private void OnSettingsDialogLoad(object sender, EventArgs args)
        {
            try
            {
                var mbHandle = MbApiInterface.MB_GetWindowHandle();
                if (mbHandle != IntPtr.Zero && _activeSettingsDialog != null)
                {
                    NativeMethods.GetWindowRect(mbHandle, out var rect);
                    int mbCenterX = rect.Left + (rect.Right - rect.Left) / 2;
                    int mbCenterY = rect.Top + (rect.Bottom - rect.Top) / 2;
                    _activeSettingsDialog.Location = new Point(
                        mbCenterX - _activeSettingsDialog.Width / 2,
                        mbCenterY - _activeSettingsDialog.Height / 2);
                }
            }
            catch (Exception ex)
            {
                LogManager.UI.Debug($"Failed to center settings dialog: {ex.Message}");
            }
        }

        #endregion

        public void Uninstall()
        {
            LogManager.Core.Info("Clouseau uninstalling...");

            try
            {
                // Check if user wants to delete data on uninstall
                bool shouldDelete = _settings?.Advanced?.DeleteDataOnUninstall ?? true;

                if (shouldDelete && !string.IsNullOrEmpty(DataPath) && Directory.Exists(DataPath))
                {
                    LogManager.Core.Info("Deleting data directory as per settings...");
                    Directory.Delete(DataPath, true);
                }
                else if (!shouldDelete)
                {
                    LogManager.Core.Info("Preserving logs and data as per user preference.");
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Uninstall cleanup failed: {ex.Message}");
            }
        }

        public void ReceiveNotification(string sourceFileUrl, NotificationType type)
        {
            // Handle plugin startup first to ensure initialization
            if (type == NotificationType.PluginStartup)
            {
                InitializePlugin();
            }

            // Route all notifications through the event logger
            _eventLogger?.HandleNotification(type);

            // Update state counters
            _stateManager?.IncrementEventCount(type.ToString());
        }

        public int OnDockablePanelCreated(Control panel)
        {
            float dpiScaling = 1.0f;
            try
            {
                using (Graphics g = panel.CreateGraphics())
                    dpiScaling = g.DpiY / 96f;
            }
            catch (Exception ex)
            {
                // Use default scaling if DPI detection fails
                LogManager.UI.Debug($"DPI detection failed, using default: {ex.Message}");
            }

            // Initialize plugin if not already done (safe on any thread)
            if (!_initialized) InitializePlugin();

            // Marshal control creation to the UI thread if called from background thread
            if (panel.InvokeRequired)
            {
                LogManager.UI.Debug("OnDockablePanelCreated called from background thread, marshaling to UI thread");
                panel.Invoke(new Action(() => CreatePanelControls(panel)));
            }
            else
            {
                CreatePanelControls(panel);
            }

            return Convert.ToInt32(250 * dpiScaling);
        }

        private void CreatePanelControls(Control panel)
        {
            try
            {
                // Hook into panel's visibility/size changes
                panel.VisibleChanged += OnHostPanelVisibleChanged;
                panel.Resize += OnHostPanelResize;

                // Create panel control on the UI thread
                _logViewerPanelControl = new LogViewerPanelControl(
                    () => _eventLogger,
                    () => _stateManager,
                    MbApiInterface,
                    OnDashboardClick,
                    OnSettingsClick);

                _logViewerPanelControl.Dock = DockStyle.Fill;
                panel.Controls.Add(_logViewerPanelControl);

                LogManager.UI.Info($"Dockable panel created successfully (size: {panel.Width}x{panel.Height}, visible: {panel.Visible})");

                // Force a refresh after a short delay
                var refreshTimer = new Timer { Interval = 500 };
                refreshTimer.Tick += (s, args) =>
                {
                    refreshTimer.Stop();
                    refreshTimer.Dispose();
                    try
                    {
                        MbApiInterface.MB_RefreshPanels?.Invoke();
                        LogManager.UI.Debug("Called MB_RefreshPanels");
                    }
                    catch (Exception ex)
                    {
                        LogManager.UI.Debug($"MB_RefreshPanels failed: {ex.Message}");
                    }
                };
                refreshTimer.Start();
            }
            catch (Exception ex)
            {
                LogManager.UI.Error(ex, "Failed to create dockable panel controls");

                // Add error label as fallback
                var errorLabel = new Label
                {
                    Text = $"Panel init failed: {ex.Message}",
                    Dock = DockStyle.Fill,
                    ForeColor = Color.Orange,
                    TextAlign = ContentAlignment.MiddleCenter
                };
                panel.Controls.Add(errorLabel);
            }
        }

        private void OnHostPanelVisibleChanged(object sender, EventArgs e)
        {
            var panel = sender as Control;
            if (panel == null || !panel.Visible) return;

            LogManager.UI.Debug($"Host panel became visible (size: {panel.Width}x{panel.Height})");

            // Force layout refresh when panel becomes visible
            if (_logViewerPanelControl != null && !_logViewerPanelControl.IsDisposed)
            {
                panel.BeginInvoke((Action)(() =>
                {
                    try
                    {
                        _logViewerPanelControl.PerformLayout();
                        _logViewerPanelControl.Invalidate(true);
                        _logViewerPanelControl.Refresh();
                    }
                    catch (Exception ex)
                    {
                        LogManager.UI.Debug($"Panel refresh failed: {ex.Message}");
                    }
                }));
            }
        }

        private void OnHostPanelResize(object sender, EventArgs e)
        {
            var panel = sender as Control;
            if (panel == null || panel.Width == 0 || panel.Height == 0) return;

            // Force child to fill when we get a real size
            if (_logViewerPanelControl != null && !_logViewerPanelControl.IsDisposed)
            {
                if (_logViewerPanelControl.Width != panel.ClientSize.Width ||
                    _logViewerPanelControl.Height != panel.ClientSize.Height)
                {
                    _logViewerPanelControl.Size = panel.ClientSize;
                    _logViewerPanelControl.Invalidate(true);
                }
            }
        }

        private void OnDashboardClick(object sender, EventArgs e)
        {
            try
            {
                if (!_initialized) InitializePlugin();
                if (string.IsNullOrEmpty(DataPath))
                {
                    MessageBox.Show("Plugin not fully initialized yet.", "Clouseau", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }

                var pluginsPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                var dashboard = new Clouseau.UI.DashboardForm(
                    MbApiInterface,
                    DataPath,
                    pluginsPath,
                    _settings,
                    _stateManager,
                    _metricsCollector,
                    _eventLogger);
                dashboard.Show(); // Non-modal
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Failed to open dashboard: {ex.Message}", "Clouseau Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void OnLiveEventsClick(object sender, EventArgs e)
        {
            try
            {
                if (!_initialized) InitializePlugin();

                // Open pop-out log viewer window
                var window = new LogViewerWindow(
                    () => _eventLogger,
                    () => _stateManager,
                    OnDashboardClick);
                window.Show();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Failed to open live events: {ex.Message}", "Clouseau Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }

    // DashboardForm with full Spy, Handlers, Invoke tabs is in UI/DashboardForm.cs

    /// <summary>
    /// Represents a log entry for display in the UI.
    /// </summary>
    public class LogDisplayEntry
    {
        public DateTime Timestamp { get; set; }
        public string Category { get; set; }
        public string Level { get; set; }
        public string Message { get; set; }
        public string SourceFile { get; set; }
        public string EventType { get; set; }
        public int EventTypeValue { get; set; }
        public long SequenceNumber { get; set; }
        public Dictionary<string, object> Context { get; set; }

        public override string ToString()
        {
            return $"{Timestamp:HH:mm:ss} [{Category}] {Message}";
        }

        /// <summary>
        /// Formats the context data for display.
        /// </summary>
        public string FormatContext()
        {
            if (Context == null || Context.Count == 0)
                return "(no context data)";

            var sb = new System.Text.StringBuilder();
            foreach (var kvp in Context)
            {
                var value = kvp.Value?.ToString() ?? "(null)";
                // Truncate long values for display
                if (value.Length > 200)
                    value = value.Substring(0, 197) + "...";
                sb.AppendLine($"  {kvp.Key}: {value}");
            }
            return sb.ToString().TrimEnd();
        }
    }

    /// <summary>
    /// Log viewer panel with lazy initialization support (like TrueShuffle ProgressPanel).
    /// </summary>
    public class LogViewerPanelControl : UserControl
    {
        private readonly Func<Clouseau.Logging.EventLogger> _getEventLogger;
        private readonly Func<Clouseau.Core.StateManager> _getStateManager;
        private readonly EventHandler _onDashboardClick;
        private readonly EventHandler _onSettingsClick;

        private ListBox _logListBox;
        private Label _statusLabel;
        private ComboBox _categoryCombo;
        private CheckBox _autoScrollCheck;
        private Timer _refreshTimer;
        private int _lastKnownBufferCount;
        private bool _subscribed;

        public LogViewerPanelControl(
            Func<Clouseau.Logging.EventLogger> getEventLogger,
            Func<Clouseau.Core.StateManager> getStateManager,
            Plugin.MusicBeeApiInterface mbApi,
            EventHandler onDashboardClick,
            EventHandler onSettingsClick)
        {
            _getEventLogger = getEventLogger;
            _getStateManager = getStateManager;
            _onDashboardClick = onDashboardClick;
            _onSettingsClick = onSettingsClick;
            InitializeComponents(mbApi);
        }

        private void InitializeComponents(Plugin.MusicBeeApiInterface mbApi)
        {
            BackColor = Color.FromArgb(30, 30, 30);

            // Get skin colors
            Color foreColor = Color.White;
            try
            {
                int colorValue = mbApi.Setting_GetSkinElementColour(
                    Plugin.SkinElement.SkinInputPanelLabel,
                    Plugin.ElementState.ElementStateDefault,
                    Plugin.ElementComponent.ComponentForeground);
                foreColor = Color.FromArgb(colorValue);
            }
            catch (Exception ex)
            {
                LogManager.UI.Debug($"Failed to get skin color: {ex.Message}");
            }

            // Header - FlowLayoutPanel for automatic spacing
            var header = new FlowLayoutPanel
            {
                Height = 44,
                Dock = DockStyle.Top,
                FlowDirection = FlowDirection.LeftToRight,
                WrapContents = false,
                Padding = new Padding(8, 8, 8, 8),
                BackColor = Color.FromArgb(45, 45, 45)
            };

            _categoryCombo = new ComboBox
            {
                Size = new Size(105, 28),
                Margin = new Padding(40, 0, 8, 0),
                DropDownStyle = ComboBoxStyle.DropDownList,
                BackColor = Color.FromArgb(50, 50, 50),
                ForeColor = Color.White,
                FlatStyle = FlatStyle.Flat,
                Font = new Font("Segoe UI", 9f)
            };
            _categoryCombo.Items.AddRange(new[] { "All", "Core", "Player", "Queue", "Library", "Tags", "Playlist", "Download", "Sync", "UI", "System" });
            _categoryCombo.SelectedIndex = 0;
            _categoryCombo.SelectedIndexChanged += (s, e) => RefreshDisplay();

            var lnkClear = new LinkLabel
            {
                Text = "Clear",
                AutoSize = true,
                Margin = new Padding(15, 6, 12, 0),
                LinkColor = Color.FromArgb(255, 120, 120),
                ActiveLinkColor = Color.White,
                VisitedLinkColor = Color.FromArgb(255, 120, 120),
                Font = new Font("Segoe UI", 9f)
            };
            lnkClear.LinkClicked += (s, e) => { _logListBox.Items.Clear(); };

            var lnkDash = new LinkLabel
            {
                Text = "Dashboard",
                AutoSize = true,
                Margin = new Padding(0, 6, 12, 0),
                LinkColor = Color.FromArgb(100, 180, 255),
                ActiveLinkColor = Color.White,
                VisitedLinkColor = Color.FromArgb(100, 180, 255),
                Font = new Font("Segoe UI", 9f),
                MinimumSize = new Size(80, 0)
            };
            lnkDash.LinkClicked += (s, e) => _onDashboardClick?.Invoke(s, e);

            var lnkPopOut = new LinkLabel
            {
                Text = "Pop Out",
                AutoSize = true,
                Margin = new Padding(0, 6, 12, 0),
                LinkColor = Color.FromArgb(100, 255, 150),
                ActiveLinkColor = Color.White,
                VisitedLinkColor = Color.FromArgb(100, 255, 150),
                Font = new Font("Segoe UI", 9f)
            };
            lnkPopOut.LinkClicked += (s, e) => PopOutToWindow();

            var lnkSettings = new LinkLabel
            {
                Text = "Settings",
                AutoSize = true,
                Margin = new Padding(0, 6, 12, 0),
                LinkColor = Color.FromArgb(255, 200, 100),
                ActiveLinkColor = Color.White,
                VisitedLinkColor = Color.FromArgb(255, 200, 100),
                Font = new Font("Segoe UI", 9f)
            };
            lnkSettings.LinkClicked += (s, e) => _onSettingsClick?.Invoke(s, e);

            _autoScrollCheck = new CheckBox
            {
                Text = "Auto-scroll",
                AutoSize = true,
                Margin = new Padding(15, 4, 10, 0),
                Checked = true,
                ForeColor = foreColor,
                Font = new Font("Segoe UI", 9f),
                MinimumSize = new Size(100, 0)
            };

            header.Controls.AddRange(new Control[] { _categoryCombo, lnkClear, lnkDash, lnkPopOut, lnkSettings, _autoScrollCheck });

            // Log list - larger font for readability
            // NOTE: Using Normal draw mode - owner-draw has issues on MusicBee startup
            _logListBox = new ListBox
            {
                Dock = DockStyle.Fill,
                BackColor = Color.FromArgb(30, 30, 30),
                ForeColor = Color.FromArgb(180, 220, 180),  // Default green color
                BorderStyle = BorderStyle.None,
                Font = new Font("Consolas", 10f),
                IntegralHeight = false,
                SelectionMode = SelectionMode.One,
                HorizontalScrollbar = true
            };

            // Status bar
            var statusBar = new Panel
            {
                Height = 36,
                Dock = DockStyle.Bottom,
                BackColor = Color.FromArgb(45, 45, 45)
            };

            _statusLabel = new Label
            {
                Text = "Initializing...",
                Location = new Point(10, 8),
                AutoSize = true,
                ForeColor = Color.LightGray,
                Font = new Font("Segoe UI", 10f)
            };
            statusBar.Controls.Add(_statusLabel);

            Controls.Add(_logListBox);
            Controls.Add(header);
            Controls.Add(statusBar);

            // Timer for lazy updates
            _refreshTimer = new Timer { Interval = 500 };
            _refreshTimer.Tick += (s, e) => UpdateDisplay();
            _refreshTimer.Start();

            // Force full repaint when control becomes visible (MusicBee startup fix)
            VisibleChanged += OnVisibleChanged;
            ParentChanged += OnParentChanged;
        }

        private void OnVisibleChanged(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine($"[Clouseau] VisibleChanged: Visible={Visible}, Handle={IsHandleCreated}, Size={Width}x{Height}");

            if (Visible && IsHandleCreated)
            {
                // MusicBee may not have fully laid out the panel yet
                BeginInvoke(new Action(() =>
                {
                    System.Diagnostics.Debug.WriteLine($"[Clouseau] Deferred refresh: Parent={Parent?.GetType().Name}, Size={Width}x{Height}");
                    _subscribed = false; // Force re-subscribe
                    UpdateDisplay();
                    _logListBox.Invalidate();
                    _logListBox.Refresh();
                    Invalidate(true);
                    Refresh();
                }));
            }
        }

        private void OnParentChanged(object sender, EventArgs e)
        {
            if (Parent != null && Visible)
            {
                BeginInvoke(new Action(() =>
                {
                    _subscribed = false;
                    UpdateDisplay();
                    Refresh();
                }));
            }
        }

        private void UpdateDisplay()
        {
            var eventLogger = _getEventLogger();
            var stateManager = _getStateManager();

            System.Diagnostics.Debug.WriteLine($"[Clouseau] UpdateDisplay: EventLogger={(eventLogger != null ? "OK" : "NULL")}, Subscribed={_subscribed}, Items={_logListBox?.Items.Count ?? -1}");

            if (eventLogger == null)
            {
                _statusLabel.Text = "Waiting for init...";
                // Add a visible message so user knows panel is alive
                if (_logListBox.Items.Count == 0)
                {
                    _logListBox.Items.Add(new LogDisplayEntry
                    {
                        Timestamp = DateTime.Now,
                        Category = "System",
                        Level = "Info",
                        Message = "Panel active - waiting for EventLogger...",
                        SourceFile = ""
                    });
                    _logListBox.Invalidate();
                    System.Diagnostics.Debug.WriteLine("[Clouseau] Added waiting message");
                }
                return;
            }

            // Subscribe to events once available
            if (!_subscribed)
            {
                eventLogger.LogEntryAdded += OnLogEntryAdded;
                _subscribed = true;

                _logListBox.BeginUpdate();
                _logListBox.Items.Clear();
                _logListBox.Items.Add(new LogDisplayEntry
                {
                    Timestamp = DateTime.Now,
                    Category = "Core",
                    Level = "Info",
                    Message = "EventLogger connected! Events will appear here.",
                    SourceFile = ""
                });

                // Load any existing buffered entries
                var existing = eventLogger.Buffer?.GetRecent(50);
                if (existing != null)
                {
                    foreach (var entry in existing)
                    {
                        _logListBox.Items.Add(new LogDisplayEntry
                        {
                            Timestamp = entry.Timestamp,
                            Category = entry.Category,
                            Level = entry.Level,
                            Message = entry.Message,
                            SourceFile = entry.SourceFile,
                            EventType = entry.EventType,
                            EventTypeValue = entry.EventTypeValue,
                            SequenceNumber = entry.SequenceNumber,
                            Context = entry.Context
                        });
                    }
                }
                _logListBox.EndUpdate();
                _logListBox.Invalidate();
                _logListBox.Refresh();
            }

            // Update status
            var bufferCount = eventLogger.Buffer?.Count ?? 0;
            var totalEvents = stateManager?.TotalEventCount ?? 0;
            _statusLabel.Text = $"Events: {totalEvents} | Buffer: {bufferCount} | Shown: {_logListBox.Items.Count}";
        }

        private void RefreshDisplay()
        {
            var eventLogger = _getEventLogger();
            if (eventLogger?.Buffer == null) return;

            _logListBox.BeginUpdate();
            _logListBox.Items.Clear();
            var filter = _categoryCombo?.SelectedItem?.ToString() ?? "All";
            var entries = eventLogger.Buffer.GetRecent(200);

            foreach (var entry in entries)
            {
                if (filter != "All" && !string.Equals(entry.Category, filter, StringComparison.OrdinalIgnoreCase))
                    continue;

                _logListBox.Items.Add(new LogDisplayEntry
                {
                    Timestamp = entry.Timestamp,
                    Category = entry.Category,
                    Level = entry.Level,
                    Message = entry.Message,
                    SourceFile = entry.SourceFile,
                    EventType = entry.EventType,
                    EventTypeValue = entry.EventTypeValue,
                    SequenceNumber = entry.SequenceNumber,
                    Context = entry.Context
                });
            }
            _logListBox.EndUpdate();

            if (_autoScrollCheck?.Checked == true && _logListBox.Items.Count > 0)
                _logListBox.TopIndex = _logListBox.Items.Count - 1;

            _logListBox.Invalidate();
        }

        private void OnLogEntryAdded(object sender, Clouseau.Logging.LogEntry entry)
        {
            if (_logListBox == null || _logListBox.IsDisposed) return;

            try
            {
                if (_logListBox.InvokeRequired)
                    _logListBox.BeginInvoke(new Action(() => AddEntry(entry)));
                else
                    AddEntry(entry);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Log entry add failed: {ex.Message}");
            }
        }

        private void AddEntry(Clouseau.Logging.LogEntry entry)
        {
            var filter = _categoryCombo?.SelectedItem?.ToString() ?? "All";
            if (filter != "All" && !string.Equals(entry.Category, filter, StringComparison.OrdinalIgnoreCase))
                return;

            _logListBox.Items.Add(new LogDisplayEntry
            {
                Timestamp = entry.Timestamp,
                Category = entry.Category,
                Level = entry.Level,
                Message = entry.Message,
                SourceFile = entry.SourceFile,
                EventType = entry.EventType,
                EventTypeValue = entry.EventTypeValue,
                SequenceNumber = entry.SequenceNumber,
                Context = entry.Context
            });

            // Keep max 300 items
            while (_logListBox.Items.Count > 300)
                _logListBox.Items.RemoveAt(0);

            if (_autoScrollCheck?.Checked == true && _logListBox.Items.Count > 0)
                _logListBox.TopIndex = _logListBox.Items.Count - 1;
        }

        private void LogListBox_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0) return;
            e.DrawBackground();

            var item = _logListBox.Items[e.Index] as LogDisplayEntry;
            Color textColor = Color.FromArgb(180, 220, 180);

            if (item != null)
            {
                switch (item.Level?.ToLowerInvariant())
                {
                    case "error": textColor = Color.FromArgb(255, 100, 100); break;
                    case "warn":
                    case "warning": textColor = Color.FromArgb(255, 200, 100); break;
                    case "debug": textColor = Color.FromArgb(150, 150, 150); break;
                }
            }

            using (var brush = new SolidBrush(textColor))
                e.Graphics.DrawString(item?.ToString() ?? "", e.Font, brush, e.Bounds);

            e.DrawFocusRectangle();
        }

        private void PopOutToWindow()
        {
            var window = new LogViewerWindow(_getEventLogger, _getStateManager, _onDashboardClick);
            window.Show();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _refreshTimer?.Stop();
                _refreshTimer?.Dispose();

                var eventLogger = _getEventLogger();
                if (eventLogger != null && _subscribed)
                    eventLogger.LogEntryAdded -= OnLogEntryAdded;
            }
            base.Dispose(disposing);
        }
    }

    /// <summary>
    /// Full-size pop-out window for the log viewer.
    /// </summary>
    public class LogViewerWindow : Form
    {
        private readonly Func<Clouseau.Logging.EventLogger> _getEventLogger;
        private readonly Func<Clouseau.Core.StateManager> _getStateManager;
        private readonly EventHandler _onDashboardClick;

        private ListBox _logListBox;
        private Label _statusLabel;
        private ComboBox _categoryCombo;
        private CheckBox _autoScrollCheck;
        private Timer _refreshTimer;
        private bool _subscribed;

        public LogViewerWindow(
            Func<Clouseau.Logging.EventLogger> getEventLogger,
            Func<Clouseau.Core.StateManager> getStateManager,
            EventHandler onDashboardClick)
        {
            _getEventLogger = getEventLogger;
            _getStateManager = getStateManager;
            _onDashboardClick = onDashboardClick;
            InitializeComponents();
        }

        private void InitializeComponents()
        {
            Text = "Clouseau - Live Event Log";
            Size = new Size(1350, 700);
            MinimumSize = new Size(900, 500);
            FormBorderStyle = FormBorderStyle.Sizable;
            StartPosition = FormStartPosition.CenterScreen;
            BackColor = Color.FromArgb(30, 30, 30);
            ForeColor = Color.White;
            Icon = SystemIcons.Information;

            // Toolbar - FlowLayoutPanel for automatic spacing
            var toolbar = new FlowLayoutPanel
            {
                Height = 60,
                Dock = DockStyle.Top,
                BackColor = Color.FromArgb(45, 45, 45),
                Padding = new Padding(10, 10, 10, 5),
                WrapContents = false
            };

            var lblFilter = new Label
            {
                Text = "Filter:",
                AutoSize = true,
                ForeColor = Color.White,
                Font = new Font("Segoe UI", 11f),
                Margin = new Padding(0, 8, 5, 0)
            };

            _categoryCombo = new ComboBox
            {
                Size = new Size(150, 36),
                DropDownStyle = ComboBoxStyle.DropDownList,
                BackColor = Color.FromArgb(50, 50, 50),
                ForeColor = Color.White,
                FlatStyle = FlatStyle.Flat,
                Font = new Font("Segoe UI", 11f),
                Margin = new Padding(0, 2, 10, 0)
            };
            _categoryCombo.Items.AddRange(new[] { "All", "Core", "Player", "Queue", "Library", "Tags", "Playlist", "Download", "Sync", "UI", "System" });
            _categoryCombo.SelectedIndex = 0;
            _categoryCombo.SelectedIndexChanged += (s, e) => RefreshDisplay();

            _autoScrollCheck = new CheckBox
            {
                Text = "Auto-scroll",
                Size = new Size(180, 40),
                Checked = true,
                ForeColor = Color.White,
                Font = new Font("Segoe UI", 10f),
                Margin = new Padding(0, 0, 10, 0)
            };

            var btnClear = new Button
            {
                Text = "Clear",
                Size = new Size(140, 40),
                FlatStyle = FlatStyle.Flat,
                ForeColor = Color.White,
                BackColor = Color.FromArgb(60, 60, 60),
                Font = new Font("Segoe UI", 10f),
                Margin = new Padding(0, 0, 5, 0)
            };
            btnClear.FlatAppearance.BorderSize = 1;
            btnClear.Click += (s, e) => { _logListBox.Items.Clear(); };

            var btnRefresh = new Button
            {
                Text = "Refresh",
                Size = new Size(160, 40),
                FlatStyle = FlatStyle.Flat,
                ForeColor = Color.White,
                BackColor = Color.FromArgb(60, 60, 60),
                Font = new Font("Segoe UI", 10f),
                Margin = new Padding(0, 0, 5, 0)
            };
            btnRefresh.FlatAppearance.BorderSize = 1;
            btnRefresh.Click += (s, e) => RefreshDisplay();

            var btnDashboard = new Button
            {
                Text = "Dashboard",
                Size = new Size(200, 40),
                FlatStyle = FlatStyle.Flat,
                ForeColor = Color.White,
                BackColor = Color.FromArgb(70, 130, 180),
                Font = new Font("Segoe UI", 10f),
                Margin = new Padding(0, 0, 10, 0)
            };
            btnDashboard.FlatAppearance.BorderSize = 1;
            btnDashboard.Click += _onDashboardClick;

            var lblHint = new Label
            {
                Text = "(double-click for details)",
                AutoSize = true,
                ForeColor = Color.Gray,
                Font = new Font("Segoe UI", 9f),
                Margin = new Padding(0, 10, 0, 0)
            };

            toolbar.Controls.AddRange(new Control[] { lblFilter, _categoryCombo, _autoScrollCheck, btnClear, btnRefresh, btnDashboard, lblHint });

            // Log list - full size with larger font and taller rows
            _logListBox = new ListBox
            {
                Dock = DockStyle.Fill,
                BackColor = Color.FromArgb(25, 25, 25),
                ForeColor = Color.FromArgb(220, 220, 220),
                BorderStyle = BorderStyle.None,
                Font = new Font("Consolas", 11f),
                IntegralHeight = false,
                SelectionMode = SelectionMode.One,
                HorizontalScrollbar = true,
                DrawMode = DrawMode.OwnerDrawFixed,
                ItemHeight = 32
            };
            _logListBox.DrawItem += LogListBox_DrawItem;
            _logListBox.DoubleClick += LogListBox_DoubleClick;

            // Status bar
            var statusBar = new Panel
            {
                Height = 40,
                Dock = DockStyle.Bottom,
                BackColor = Color.FromArgb(45, 45, 45)
            };

            _statusLabel = new Label
            {
                Text = "Initializing...",
                Dock = DockStyle.Fill,
                TextAlign = ContentAlignment.MiddleLeft,
                Padding = new Padding(15, 0, 0, 0),
                ForeColor = Color.LightGray,
                Font = new Font("Segoe UI", 11f)
            };
            statusBar.Controls.Add(_statusLabel);

            // Dock order: Fill first, then Bottom, then Top last
            Controls.Add(_logListBox);
            Controls.Add(statusBar);
            Controls.Add(toolbar);

            // Timer for updates
            _refreshTimer = new Timer { Interval = 500 };
            _refreshTimer.Tick += (s, e) => UpdateDisplay();
            _refreshTimer.Start();

            // Initial load
            RefreshDisplay();
        }

        private void UpdateDisplay()
        {
            var eventLogger = _getEventLogger();
            var stateManager = _getStateManager();

            if (eventLogger == null)
            {
                _statusLabel.Text = "Waiting for EventLogger...";
                return;
            }

            // Subscribe to events once available
            if (!_subscribed)
            {
                eventLogger.LogEntryAdded += OnLogEntryAdded;
                _subscribed = true;
                RefreshDisplay();
            }

            // Update status
            var bufferCount = eventLogger.Buffer?.Count ?? 0;
            var totalEvents = stateManager?.TotalEventCount ?? 0;
            _statusLabel.Text = $"Total Events: {totalEvents}  |  Buffer: {bufferCount}  |  Displayed: {_logListBox.Items.Count}";
        }

        private void RefreshDisplay()
        {
            var eventLogger = _getEventLogger();
            if (eventLogger?.Buffer == null) return;

            _logListBox.Items.Clear();
            var filter = _categoryCombo?.SelectedItem?.ToString() ?? "All";
            var entries = eventLogger.Buffer.GetRecent(500);

            foreach (var entry in entries)
            {
                if (filter != "All" && !string.Equals(entry.Category, filter, StringComparison.OrdinalIgnoreCase))
                    continue;

                _logListBox.Items.Add(new LogDisplayEntry
                {
                    Timestamp = entry.Timestamp,
                    Category = entry.Category,
                    Level = entry.Level,
                    Message = entry.Message,
                    SourceFile = entry.SourceFile,
                    EventType = entry.EventType,
                    EventTypeValue = entry.EventTypeValue,
                    SequenceNumber = entry.SequenceNumber,
                    Context = entry.Context
                });
            }

            if (_autoScrollCheck?.Checked == true && _logListBox.Items.Count > 0)
                _logListBox.TopIndex = _logListBox.Items.Count - 1;
        }

        private void OnLogEntryAdded(object sender, Clouseau.Logging.LogEntry entry)
        {
            if (_logListBox == null || _logListBox.IsDisposed) return;

            try
            {
                if (_logListBox.InvokeRequired)
                    _logListBox.BeginInvoke(new Action(() => AddEntry(entry)));
                else
                    AddEntry(entry);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Log entry add failed: {ex.Message}");
            }
        }

        private void AddEntry(Clouseau.Logging.LogEntry entry)
        {
            var filter = _categoryCombo?.SelectedItem?.ToString() ?? "All";
            if (filter != "All" && !string.Equals(entry.Category, filter, StringComparison.OrdinalIgnoreCase))
                return;

            _logListBox.Items.Add(new LogDisplayEntry
            {
                Timestamp = entry.Timestamp,
                Category = entry.Category,
                Level = entry.Level,
                Message = entry.Message,
                SourceFile = entry.SourceFile,
                EventType = entry.EventType,
                EventTypeValue = entry.EventTypeValue,
                SequenceNumber = entry.SequenceNumber,
                Context = entry.Context
            });

            // Keep max 1000 items in pop-out window
            while (_logListBox.Items.Count > 1000)
                _logListBox.Items.RemoveAt(0);

            if (_autoScrollCheck?.Checked == true && _logListBox.Items.Count > 0)
                _logListBox.TopIndex = _logListBox.Items.Count - 1;
        }

        private void LogListBox_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0) return;
            e.DrawBackground();

            var item = _logListBox.Items[e.Index] as LogDisplayEntry;
            Color textColor = Color.FromArgb(180, 220, 180);

            if (item != null)
            {
                switch (item.Level?.ToLowerInvariant())
                {
                    case "error": textColor = Color.FromArgb(255, 100, 100); break;
                    case "warn":
                    case "warning": textColor = Color.FromArgb(255, 200, 100); break;
                    case "debug": textColor = Color.FromArgb(120, 120, 120); break;
                    case "info": textColor = Color.FromArgb(180, 220, 180); break;
                }

                // Color code by category too
                switch (item.Category?.ToLowerInvariant())
                {
                    case "player": textColor = Color.FromArgb(100, 200, 255); break;
                    case "queue": textColor = Color.FromArgb(200, 150, 255); break;
                    case "tags": textColor = Color.FromArgb(255, 180, 100); break;
                }
            }

            var text = item != null
                ? $"{item.Timestamp:HH:mm:ss.fff} [{item.Category,-8}] [{item.Level,-5}] {item.Message}"
                : "";

            using (var brush = new SolidBrush(textColor))
                e.Graphics.DrawString(text, e.Font, brush, e.Bounds.X + 4, e.Bounds.Y + 2);

            e.DrawFocusRectangle();
        }

        private void LogListBox_DoubleClick(object sender, EventArgs e)
        {
            var item = _logListBox.SelectedItem as LogDisplayEntry;
            if (item == null) return;

            var sb = new System.Text.StringBuilder();
            sb.AppendLine($"═══════════════════════════════════════════════════════════");
            sb.AppendLine($"  EVENT DETAILS  (Seq #{item.SequenceNumber})");
            sb.AppendLine($"═══════════════════════════════════════════════════════════");
            sb.AppendLine();
            sb.AppendLine($"Timestamp:  {item.Timestamp:yyyy-MM-dd HH:mm:ss.fff}");
            sb.AppendLine($"Category:   {item.Category}");
            sb.AppendLine($"Event:      {item.EventType} ({item.EventTypeValue})");
            sb.AppendLine($"Level:      {item.Level}");
            sb.AppendLine($"Message:    {item.Message}");
            if (!string.IsNullOrEmpty(item.SourceFile))
                sb.AppendLine($"Source:     {item.SourceFile}");
            sb.AppendLine();
            sb.AppendLine($"───────────────────────────────────────────────────────────");
            sb.AppendLine($"  CONTEXT DATA");
            sb.AppendLine($"───────────────────────────────────────────────────────────");
            sb.AppendLine();
            sb.AppendLine(item.FormatContext());

            // Use a scrollable form instead of MessageBox for long content
            using (var detailsForm = new Form
            {
                Text = $"Event Details - {item.EventType}",
                Size = new Size(700, 550),
                StartPosition = FormStartPosition.CenterParent,
                BackColor = Color.FromArgb(30, 30, 30),
                ForeColor = Color.White,
                FormBorderStyle = FormBorderStyle.Sizable,
                MinimumSize = new Size(500, 400)
            })
            {
                var textBox = new TextBox
                {
                    Multiline = true,
                    ReadOnly = true,
                    Dock = DockStyle.Fill,
                    ScrollBars = ScrollBars.Both,
                    BackColor = Color.FromArgb(25, 25, 25),
                    ForeColor = Color.FromArgb(220, 220, 220),
                    Font = new Font("Consolas", 10f),
                    Text = sb.ToString(),
                    WordWrap = false
                };
                detailsForm.Controls.Add(textBox);
                detailsForm.ShowDialog(this);
            }
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            _refreshTimer?.Stop();
            _refreshTimer?.Dispose();

            var eventLogger = _getEventLogger();
            if (eventLogger != null && _subscribed)
                eventLogger.LogEntryAdded -= OnLogEntryAdded;

            base.OnFormClosing(e);
        }
    }
}
