using System;
using System.Drawing;
using System.Windows.Forms;
using Elfisa.UI.Theming;

namespace Elfisa.UI.Controls
{
    public class ModernDataGridView : DataGridView
    {
        private ThemeColors _theme;
        private int? _hoverRowIndex;

        public ModernDataGridView()
        {
            EnableHeadersVisualStyles = false;
            BorderStyle = BorderStyle.None;
            CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal;
            RowHeadersVisible = false;
            SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            MultiSelect = false;
            AllowUserToAddRows = false;
            AllowUserToResizeRows = false;
            AllowUserToResizeColumns = true;
            AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
            AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
            ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
            RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;
            ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.None;
            DoubleBuffered = true;
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
            CellFormatting += OnGridCellFormatting;
            ApplyTheme(ThemeManager.Colors);
        }

        public new DataGridViewAutoSizeRowsMode AutoSizeRowsMode
        {
            get => base.AutoSizeRowsMode;
            set => base.AutoSizeRowsMode = NormalizeAutoSizeRowsMode(value);
        }

        public new DataGridViewRowHeadersWidthSizeMode RowHeadersWidthSizeMode
        {
            get => base.RowHeadersWidthSizeMode;
            set => base.RowHeadersWidthSizeMode = NormalizeRowHeadersWidthSizeMode(value);
        }

        private DataGridViewAutoSizeRowsMode NormalizeAutoSizeRowsMode(DataGridViewAutoSizeRowsMode value)
        {
            if (!RowHeadersVisible &&
                (value == DataGridViewAutoSizeRowsMode.DisplayedHeaders ||
                 value == DataGridViewAutoSizeRowsMode.AllHeaders))
            {
                return DataGridViewAutoSizeRowsMode.None;
            }

            return value;
        }

        private DataGridViewRowHeadersWidthSizeMode NormalizeRowHeadersWidthSizeMode(
            DataGridViewRowHeadersWidthSizeMode value)
        {
            if (!RowHeadersVisible &&
                value == DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders)
            {
                return DataGridViewRowHeadersWidthSizeMode.DisableResizing;
            }

            return value;
        }

        private void ApplyBorderStyles(ThemeColors theme)
        {
            GridColor = theme.GridBorder;

            AdvancedCellBorderStyle.All = DataGridViewAdvancedCellBorderStyle.None;
            AdvancedCellBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.Single;

            AdvancedColumnHeadersBorderStyle.All = DataGridViewAdvancedCellBorderStyle.None;
            AdvancedColumnHeadersBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.Single;

            if (Rows.Count > 0)
            {
                AdvancedRowHeadersBorderStyle.All = DataGridViewAdvancedCellBorderStyle.None;
            }
        }

        public void ApplyTheme(ThemeColors theme)
        {
            _theme = theme;
            BackgroundColor = theme.GridRowBackground;
            ApplyBorderStyles(theme);
            ColumnHeadersHeight = theme.GridHeaderHeight;
            RowTemplate.Height = theme.GridRowHeight;
            Font = theme.FontRegular13;
            ColumnHeadersDefaultCellStyle = new DataGridViewCellStyle
            {
                BackColor = theme.GridHeaderBackground,
                ForeColor = theme.GridHeaderForeground,
                Font = theme.FontSemibold14,
                Alignment = DataGridViewContentAlignment.MiddleLeft,
                Padding = new Padding(12, 0, 12, 0),
                SelectionBackColor = theme.GridHeaderBackground,
                SelectionForeColor = theme.GridHeaderForeground
            };
            DefaultCellStyle = new DataGridViewCellStyle
            {
                BackColor = theme.GridRowBackground,
                ForeColor = theme.TextPrimary,
                SelectionBackColor = theme.GridRowSelected,
                SelectionForeColor = theme.GridRowSelectedText,
                Font = theme.FontRegular13,
                Padding = new Padding(12, 0, 12, 0),
                WrapMode = DataGridViewTriState.False
            };
            AlternatingRowsDefaultCellStyle = new DataGridViewCellStyle
            {
                BackColor = theme.GridRowAlternate,
                ForeColor = theme.TextPrimary,
                SelectionBackColor = theme.GridRowSelected,
                SelectionForeColor = theme.GridRowSelectedText,
                Font = theme.FontRegular13,
                Padding = new Padding(12, 0, 12, 0)
            };
            Invalidate(true);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            var theme = _theme ?? ThemeManager.Colors;
            using (var pen = new Pen(theme.GridBorder))
            {
                var rect = new Rectangle(0, 0, ClientSize.Width - 1, ClientSize.Height - 1);
                e.Graphics.DrawRectangle(pen, rect);
            }
        }

        protected override void OnRowsAdded(DataGridViewRowsAddedEventArgs e)
        {
            base.OnRowsAdded(e);
            ApplyBorderStyles(_theme ?? ThemeManager.Colors);
        }

        private void OnGridCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.RowIndex < 0 || e.ColumnIndex < 0)
            {
                return;
            }

            var theme = _theme ?? ThemeManager.Colors;
            var row = Rows[e.RowIndex];

            if (row.Selected)
            {
                e.CellStyle.BackColor = theme.GridRowSelected;
                e.CellStyle.ForeColor = theme.GridRowSelectedText;
            }
            else if (_hoverRowIndex == e.RowIndex)
            {
                e.CellStyle.BackColor = theme.GridRowHover;
                e.CellStyle.ForeColor = theme.TextPrimary;
            }
            else if (e.RowIndex % 2 == 1)
            {
                e.CellStyle.BackColor = theme.GridRowAlternate;
                e.CellStyle.ForeColor = theme.TextPrimary;
            }
            else
            {
                e.CellStyle.BackColor = theme.GridRowBackground;
                e.CellStyle.ForeColor = theme.TextPrimary;
            }

            e.CellStyle.SelectionBackColor = theme.GridRowSelected;
            e.CellStyle.SelectionForeColor = theme.GridRowSelectedText;
            e.CellStyle.Font = theme.FontRegular13;
        }

        protected override void OnDataSourceChanged(EventArgs e)
        {
            _hoverRowIndex = null;
            base.OnDataSourceChanged(e);
        }

        protected override void OnCellMouseEnter(DataGridViewCellEventArgs e)
        {
            base.OnCellMouseEnter(e);
            if (e.RowIndex < 0 || e.RowIndex == _hoverRowIndex)
            {
                return;
            }

            var previous = _hoverRowIndex;
            _hoverRowIndex = e.RowIndex;
            InvalidateRowSafe(previous);
            InvalidateRowSafe(e.RowIndex);
        }

        protected override void OnCellMouseLeave(DataGridViewCellEventArgs e)
        {
            base.OnCellMouseLeave(e);
            if (e.RowIndex < 0 || _hoverRowIndex != e.RowIndex)
            {
                return;
            }

            _hoverRowIndex = null;
            InvalidateRowSafe(e.RowIndex);
        }

        private void InvalidateRowSafe(int? rowIndex)
        {
            if (!rowIndex.HasValue)
            {
                return;
            }

            var index = rowIndex.Value;
            if (index < 0 || index >= Rows.Count)
            {
                return;
            }

            InvalidateRow(index);
        }
    }
}
