// ============================================================================
// mb_clouseau - Window Tracker
// Uncovering clues with MusicBee Clouseau
//
// Tracks main window handle with Win32 details
// ============================================================================

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using MusicBeePlugin.Clouseau.Core;

namespace MusicBeePlugin.Clouseau.Introspection
{
    /// <summary>
    /// Tracks the MusicBee main window state using Win32 APIs.
    /// </summary>
    public class WindowTracker : IDisposable
    {
        private Plugin.MusicBeeApiInterface _mbApi;
        private WindowStateSnapshot _currentState;
        private readonly ConcurrentQueue<WindowStateSnapshot> _stateHistory;
        private readonly object _stateLock = new object();
        private const int MaxHistorySize = 100;
        private bool _disposed;

        // Win32 constants
        private const int WS_MINIMIZE = 0x20000000;
        private const int WS_MAXIMIZE = 0x01000000;
        private const int WS_VISIBLE = 0x10000000;
        private const int GWL_STYLE = -16;
        private const int GWL_EXSTYLE = -20;

        // Win32 imports
        [DllImport("user32.dll")]
        private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        [DllImport("user32.dll")]
        private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

        [DllImport("user32.dll")]
        private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);

        [DllImport("user32.dll")]
        private static extern bool IsWindowVisible(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern bool IsIconic(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern bool IsZoomed(IntPtr hWnd);

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

            public Rectangle ToRectangle()
                => new Rectangle(Left, Top, Right - Left, Bottom - Top);
        }

        /// <summary>
        /// Event raised when window state changes.
        /// </summary>
        public event EventHandler<WindowStateSnapshot> StateChanged;

        public WindowTracker()
        {
            _stateHistory = new ConcurrentQueue<WindowStateSnapshot>();
        }

        /// <summary>
        /// Gets the current window state.
        /// </summary>
        public WindowStateSnapshot CurrentState
        {
            get
            {
                lock (_stateLock)
                {
                    return _currentState;
                }
            }
        }

        /// <summary>
        /// Sets the MusicBee API interface.
        /// </summary>
        public void SetMusicBeeApi(Plugin.MusicBeeApiInterface mbApi)
        {
            _mbApi = mbApi;
        }

        /// <summary>
        /// Captures and returns the current window state.
        /// </summary>
        public WindowStateSnapshot CaptureState()
        {
            IntPtr handle = IntPtr.Zero;

            try
            {
                handle = _mbApi.MB_GetWindowHandle?.Invoke() ?? IntPtr.Zero;
            }
            catch
            {
                // API may not be available
            }

            if (handle == IntPtr.Zero)
            {
                return new WindowStateSnapshot
                {
                    Timestamp = DateTime.Now,
                    Handle = IntPtr.Zero,
                    IsValid = false
                };
            }

            var snapshot = CaptureWindowState(handle);

            lock (_stateLock)
            {
                var oldState = _currentState;
                _currentState = snapshot;

                // Check for significant changes
                if (oldState != null && HasSignificantChange(oldState, snapshot))
                {
                    EnqueueHistory(snapshot);
                    OnStateChanged(snapshot);
                }
                else if (oldState == null)
                {
                    EnqueueHistory(snapshot);
                }
            }

            return snapshot;
        }

        /// <summary>
        /// Captures state for a specific window handle.
        /// </summary>
        public WindowStateSnapshot CaptureWindowState(IntPtr handle)
        {
            if (handle == IntPtr.Zero)
            {
                return new WindowStateSnapshot
                {
                    Timestamp = DateTime.Now,
                    Handle = IntPtr.Zero,
                    IsValid = false
                };
            }

            var snapshot = new WindowStateSnapshot
            {
                Timestamp = DateTime.Now,
                Handle = handle,
                IsValid = true
            };

            try
            {
                // Get window rectangle
                if (GetWindowRect(handle, out var windowRect))
                {
                    snapshot.Bounds = windowRect.ToRectangle();
                }

                // Get client rectangle
                if (GetClientRect(handle, out var clientRect))
                {
                    snapshot.ClientArea = clientRect.ToRectangle();
                }

                // Get window styles
                snapshot.Style = GetWindowLong(handle, GWL_STYLE);
                snapshot.ExStyle = GetWindowLong(handle, GWL_EXSTYLE);

                // Get state flags
                snapshot.IsVisible = IsWindowVisible(handle);
                snapshot.IsMinimized = IsIconic(handle);
                snapshot.IsMaximized = IsZoomed(handle);

                // Get window text
                var titleBuilder = new System.Text.StringBuilder(256);
                GetWindowText(handle, titleBuilder, 256);
                snapshot.Title = titleBuilder.ToString();

                // Get class name
                var classBuilder = new System.Text.StringBuilder(256);
                GetClassName(handle, classBuilder, 256);
                snapshot.ClassName = classBuilder.ToString();
            }
            catch (Exception ex)
            {
                LogManager.Core.Trace($"Error capturing window state: {ex.Message}");
                snapshot.IsValid = false;
            }

            return snapshot;
        }

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

        /// <summary>
        /// Gets a summary of window tracking.
        /// </summary>
        public WindowTrackerSummary GetSummary()
        {
            var state = CurrentState;
            var history = _stateHistory.ToArray();

            return new WindowTrackerSummary
            {
                CurrentHandle = state?.Handle ?? IntPtr.Zero,
                CurrentBounds = state?.Bounds ?? Rectangle.Empty,
                IsMinimized = state?.IsMinimized ?? false,
                IsMaximized = state?.IsMaximized ?? false,
                IsVisible = state?.IsVisible ?? false,
                WindowTitle = state?.Title,
                ClassName = state?.ClassName,
                StateChangeCount = history.Length,
                LastStateChange = history.LastOrDefault()?.Timestamp
            };
        }

        private bool HasSignificantChange(WindowStateSnapshot oldState, WindowStateSnapshot newState)
        {
            if (oldState == null || newState == null) return true;
            if (!oldState.IsValid || !newState.IsValid) return false;

            // Check for significant changes
            return oldState.IsMinimized != newState.IsMinimized ||
                   oldState.IsMaximized != newState.IsMaximized ||
                   oldState.IsVisible != newState.IsVisible ||
                   oldState.Handle != newState.Handle ||
                   Math.Abs(oldState.Bounds.Width - newState.Bounds.Width) > 10 ||
                   Math.Abs(oldState.Bounds.Height - newState.Bounds.Height) > 10;
        }

        private void EnqueueHistory(WindowStateSnapshot snapshot)
        {
            _stateHistory.Enqueue(snapshot);
            while (_stateHistory.Count > MaxHistorySize)
            {
                _stateHistory.TryDequeue(out _);
            }
        }

        protected virtual void OnStateChanged(WindowStateSnapshot snapshot)
            => StateChanged?.Invoke(this, snapshot);

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

    /// <summary>
    /// Represents a window state snapshot.
    /// </summary>
    public class WindowStateSnapshot
    {
        public DateTime Timestamp { get; set; }
        public IntPtr Handle { get; set; }
        public Rectangle Bounds { get; set; }
        public Rectangle ClientArea { get; set; }
        public int Style { get; set; }
        public int ExStyle { get; set; }
        public bool IsMinimized { get; set; }
        public bool IsMaximized { get; set; }
        public bool IsVisible { get; set; }
        public string Title { get; set; }
        public string ClassName { get; set; }
        public bool IsValid { get; set; }

        public string StyleHex => $"0x{Style:X8}";
        public string ExStyleHex => $"0x{ExStyle:X8}";
    }

    /// <summary>
    /// Summary of window tracking state.
    /// </summary>
    public class WindowTrackerSummary
    {
        public IntPtr CurrentHandle { get; set; }
        public Rectangle CurrentBounds { get; set; }
        public bool IsMinimized { get; set; }
        public bool IsMaximized { get; set; }
        public bool IsVisible { get; set; }
        public string WindowTitle { get; set; }
        public string ClassName { get; set; }
        public int StateChangeCount { get; set; }
        public DateTime? LastStateChange { get; set; }
    }
}
