using Quasar.Common.Helpers;
using Quasar.Server.Helper;
using Quasar.Server.Utilities;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Quasar.Server.Controls
{
    internal class AeroListView : ListView
    {
        private const uint WM_CHANGEUISTATE = 0x127;
        private const int WM_PAINT = 0x000F;
        private const int WM_ERASEBKGND = 0x0014;

        private const short UIS_SET = 1;
        private const short UISF_HIDEFOCUS = 0x1;
        private readonly IntPtr _removeDots = new IntPtr(NativeMethodsHelper.MakeWin32Long(UIS_SET, UISF_HIDEFOCUS));

        public ListViewColumnSorter LvwColumnSorter { get; set; }

        [DllImport("user32.dll")]
        private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        private const uint GW_CHILD = 5;
        private const int HDM_FIRST = 0x1200;
        private const int HDM_LAYOUT = HDM_FIRST + 5;

        /// <summary>
        /// Initializes a new instance of the <see cref="AeroListView"/> class.
        /// </summary>
        public AeroListView()
        {
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
            this.LvwColumnSorter = new ListViewColumnSorter();
            this.ListViewItemSorter = LvwColumnSorter;
            this.View = View.Details;
            this.FullRowSelect = true;
            this.OwnerDraw = false; // Will be set in OnHandleCreated if dark mode is enabled
        }
        
        /// <summary>
        /// Enables dark mode drawing for this ListView
        /// </summary>
        public void EnableDarkMode()
        {
            if (this.OwnerDraw) return; // Already enabled
            
            this.OwnerDraw = true;
            this.GridLines = false; // Remove gridlines
            this.DrawItem += AeroListView_DrawItem;
            this.DrawSubItem += AeroListView_DrawSubItem;
            this.DrawColumnHeader += AeroListView_DrawColumnHeader;
            this.BackColor = Color.FromArgb(37, 37, 38);
            this.ForeColor = Color.White;
            this.Invalidate();
        }

        private void AeroListView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
        {
            Color darkBg = Color.FromArgb(45, 45, 48);
            Color darkFg = Color.White;
            Color darkBorder = Color.FromArgb(63, 63, 70);
            
            e.Graphics.FillRectangle(new SolidBrush(darkBg), e.Bounds);
            
            using (Pen pen = new Pen(darkBorder))
            {
                e.Graphics.DrawRectangle(pen, e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1);
            }
            
            TextRenderer.DrawText(e.Graphics, e.Header.Text, this.Font, e.Bounds, darkFg,
                TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
        }

        private void AeroListView_DrawItem(object sender, DrawListViewItemEventArgs e)
        {
            e.DrawDefault = false;
        }

        private void AeroListView_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
        {
            Color darkBg = Color.FromArgb(45, 45, 48);
            Color darkControlBg = Color.FromArgb(37, 37, 38);
            Color darkFg = Color.White;
            Color darkHighlight = Color.FromArgb(62, 62, 64);
            
            Color backColor;
            Color foreColor = darkFg;
            
            if (e.Item.Selected)
            {
                backColor = darkHighlight;
                foreColor = Color.White;
            }
            else
            {
                backColor = darkControlBg;
                
                // Preserve custom colors like red text
                if (e.Item.ForeColor != Color.Empty && 
                    e.Item.ForeColor != SystemColors.WindowText &&
                    e.Item.ForeColor != Color.Black &&
                    e.Item.ForeColor != darkFg)
                {
                    foreColor = e.Item.ForeColor;
                }
                else if (e.SubItem.ForeColor != Color.Empty && 
                         e.SubItem.ForeColor != SystemColors.WindowText &&
                         e.SubItem.ForeColor != Color.Black &&
                         e.SubItem.ForeColor != darkFg)
                {
                    foreColor = e.SubItem.ForeColor;
                }
            }
            
            using (SolidBrush brush = new SolidBrush(backColor))
            {
                e.Graphics.FillRectangle(brush, e.Bounds);
            }
            
            if (!string.IsNullOrEmpty(e.SubItem.Text))
            {
                TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.Item.Font, e.Bounds, foreColor,
                    TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix);
            }
        }

        /// <summary>
        /// Raises the <see cref="E:HandleCreated" /> event.
        /// </summary>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);

            if (PlatformHelper.RunningOnMono) return;

            if (PlatformHelper.VistaOrHigher)
            {
                // set window theme to explorer (unless dark mode is enabled)
                if (!ThemeManager.DarkModeEnabled)
                {
                    NativeMethods.SetWindowTheme(this.Handle, "explorer", null);
                }
            }

            if (PlatformHelper.XpOrHigher)
            {
                // removes the ugly dotted line around focused item
                NativeMethods.SendMessage(this.Handle, WM_CHANGEUISTATE, _removeDots, IntPtr.Zero);
            }

            // Apply dark mode header styling if enabled
            if (ThemeManager.DarkModeEnabled)
            {
                ApplyDarkModeHeader();
            }
        }

        private void ApplyDarkModeHeader()
        {
            try
            {
                // Get the header control handle
                IntPtr headerHandle = GetWindow(this.Handle, GW_CHILD);
                if (headerHandle != IntPtr.Zero)
                {
                    // Set dark theme for header
                    NativeMethods.SetWindowTheme(headerHandle, "DarkMode_Explorer", null);
                }
            }
            catch
            {
                // Silently fail if header styling doesn't work
            }
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            // Custom paint the header in dark mode
            if (ThemeManager.DarkModeEnabled && m.Msg == WM_PAINT)
            {
                PaintDarkHeader();
            }
        }

        private void PaintDarkHeader()
        {
            try
            {
                IntPtr headerHandle = GetWindow(this.Handle, GW_CHILD);
                if (headerHandle != IntPtr.Zero)
                {
                    using (Graphics g = Graphics.FromHwnd(headerHandle))
                    {
                        Rectangle headerRect = new Rectangle(0, 0, this.Width, 20);
                        using (SolidBrush brush = new SolidBrush(Color.FromArgb(45, 45, 48)))
                        {
                            g.FillRectangle(brush, headerRect);
                        }

                        int x = 0;
                        using (SolidBrush textBrush = new SolidBrush(Color.White))
                        using (StringFormat sf = new StringFormat { LineAlignment = StringAlignment.Center })
                        {
                            foreach (ColumnHeader column in this.Columns)
                            {
                                Rectangle colRect = new Rectangle(x, 0, column.Width, 20);
                                g.DrawString(column.Text, this.Font, textBrush, colRect, sf);
                                x += column.Width;
                            }
                        }
                    }
                }
            }
            catch
            {
                // Silently fail
            }
        }
        
        /// <summary>
        /// Raises the <see cref="E:ColumnClick" /> event.
        /// </summary>
        /// <param name="e">The <see cref="ColumnClickEventArgs"/> instance containing the event data.</param>
        protected override void OnColumnClick(ColumnClickEventArgs e)
        {
            base.OnColumnClick(e);

            // Determine if clicked column is already the column that is being sorted.
            if (e.Column == this.LvwColumnSorter.SortColumn)
            {
                // Reverse the current sort direction for this column.
                this.LvwColumnSorter.Order = (this.LvwColumnSorter.Order == SortOrder.Ascending)
                    ? SortOrder.Descending
                    : SortOrder.Ascending;
            }
            else
            {
                // Set the column number that is to be sorted; default to ascending.
                this.LvwColumnSorter.SortColumn = e.Column;
                this.LvwColumnSorter.Order = SortOrder.Ascending;
            }

            // Perform the sort with these new sort options.
            if (!this.VirtualMode)
                this.Sort();
        }
    }
}