using Microsoft.Graphics.Canvas.Text;
using Microsoft.UI.Text;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Sonex.Client.Controls.DataGridView;

// Odpowiedzialnosc pliku: generowanie naglowkow, szerokosci kolumn i przygotowanie ukladu kolumn.

public sealed partial class DataGridView
{
    private bool _NeedGenerateHeaders = true;
    private bool _NeedCalcHeaders = true;
    private bool _IsGeneratingHeaders = false;

    private double _IndexColWidth = 26;
    private double _PinedColWidth = 0;
    private double _NotPinedColWidth = 0;
    private double _TotalColWidth = 0;
    List<Column> _Columns = new();

    public void GenerateHeaders()
    {
        if (!_NeedGenerateHeaders) return;
        if (_IsGeneratingHeaders) return;

        if (_itemType == null) return;

        //if (_items == null) return;
        _IsGeneratingHeaders = true;
        try
        {
            _Columns.Clear();
            int i = 10000;
            foreach (var prop in _itemType.GetProperties())
            {
                var column = new Column(this)
                {
                    PropertyInfo = prop,
                    Name = prop.Name,
                    Title = TextToDisplay(prop.Name),
                    Index = i++,
                    TextFormat = GetCanvasTextFormat(prop.PropertyType),
                    Root = this
                };
                _Columns.Add(column);
            }
            _NeedGenerateHeaders = false;
            ApplyLayoutFromConfiguredSource();
            RefreshColumnFilterFlags();
            _NeedCalcHeaders = true;
        }
        finally
        {
            _IsGeneratingHeaders = false;
        }
    }

    public void CalcHeaders()
    {
        if (_NeedCalcHeaders == false) return;

        _PinedColWidth = 0;
        _TotalColWidth = 0;

        _MaxIndexOnScreen = (int)Math.Ceiling((_Canvas.ActualHeight - _HeaderHeight) / _RowsHeight);
        _IndexColWidth = Math.Max(9 * DigitCount(_ItemsSourceFiltred?.Count ?? 0), 26);
        double left = _IndexColWidth;
        _Columns.Sort((x, y) => (x.Index).CompareTo(y.Index));   // ASC

        foreach (Column header in _Columns)
        {
            if (header.IsHiden)
                continue;

            if (header.ManualWidth.HasValue)
            {
                header.Width = Math.Clamp(header.ManualWidth.Value, 88d, 800d);
                header.NeedsAutoWidth = false;
            }
            else if (header.NeedsAutoWidth || header.Width == 0)
            {
                header.Width = CalculateColumnWidth(header);
                header.NeedsAutoWidth = false;
            }
            header.Left = left;
            left += header.Width;
            if (header.IsPinned)
            {
                _PinedColWidth += header.Width;
            }
            else
            {
                _NotPinedColWidth += header.Width;
            }
            _TotalColWidth += header.Width;
        }



        _NeedCalcHorizontalScroll = true;
        _NeedCalcHeaders = false;
    }




    private double CalculateColumnWidth(Column header)
    {

        if (_ItemsSourceFiltred == null) return 88;
        int w = 4;
        for (int i = 0; i < Math.Min(_ItemsSourceFiltred.Count, _MaxIndexOnScreen); i++)
        {
            var s = GetValue(i, header);
            if (string.IsNullOrEmpty(s)) continue;
            w = Math.Max(s.Length, w);
        }

        return Math.Clamp((double)(w * 8 + 24), 88, 800); // Placeholder for actual width calculation logic

    }


    private static CanvasTextFormat TextFormatLeft = new CanvasTextFormat()
    {
        FontSize = 14f,
        FontFamily = "Consolas",
        FontWeight = FontWeights.Normal,

        HorizontalAlignment = CanvasHorizontalAlignment.Left,
        VerticalAlignment = CanvasVerticalAlignment.Center,
        WordWrapping = CanvasWordWrapping.NoWrap,
        TrimmingGranularity = CanvasTextTrimmingGranularity.Character,
        TrimmingSign = CanvasTrimmingSign.Ellipsis,

        //Direction = CanvasTextDirection.LeftToRightThenBottomToTop,
    };

    private static CanvasTextFormat TextFormatRight = new CanvasTextFormat()
    {
        FontSize = 14f,
        FontFamily = "Consolas",
        FontWeight = FontWeights.Normal,

        HorizontalAlignment = CanvasHorizontalAlignment.Right,
        VerticalAlignment = CanvasVerticalAlignment.Center,
        WordWrapping = CanvasWordWrapping.NoWrap,
        TrimmingGranularity = CanvasTextTrimmingGranularity.Character,
        TrimmingSign = CanvasTrimmingSign.Ellipsis,

        //Direction = CanvasTextDirection.LeftToRightThenBottomToTop,
    };

    private static CanvasTextFormat TextFormatCenter = new CanvasTextFormat()
    {
        FontSize = 14f,
        FontFamily = "Consolas",
        FontWeight = FontWeights.Normal,

        HorizontalAlignment = CanvasHorizontalAlignment.Center,
        VerticalAlignment = CanvasVerticalAlignment.Center,
        WordWrapping = CanvasWordWrapping.NoWrap,
        TrimmingGranularity = CanvasTextTrimmingGranularity.Character,
        TrimmingSign = CanvasTrimmingSign.Ellipsis,

        //Direction = CanvasTextDirection.LeftToRightThenBottomToTop,
    };

    private static string TextToDisplay(string? text)
    {
        if (string.IsNullOrWhiteSpace(text))
            return string.Empty;

        return Regex.Replace(
            text.Trim(),
            @"(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])",
            " ");
    }
    static CanvasTextFormat GetCanvasTextFormat(Type type)
    {
        if (type == typeof(string)) return TextFormatLeft;
        if (type == typeof(string[])) return TextFormatLeft;
        if (type == typeof(Guid)) return TextFormatLeft;
        if (type == typeof(Enum)) return TextFormatLeft;
        if (type == typeof(byte[])) return TextFormatLeft;
        if (type == typeof(bool)) return TextFormatCenter;
        if (type == typeof(char)) return TextFormatCenter;

        return TextFormatRight;
    }

    static int GetWeightByType(Type type)
    {
        if (type == typeof(string)) return 0;
        if (type == typeof(string[])) return 0;
        if (type == typeof(Guid)) return 0;
        if (type == typeof(Enum)) return 0;
        if (type == typeof(byte[])) return 0;
        if (type == typeof(bool)) return 0;
        if (type == typeof(char)) return 0;

        return 0;
    }
    static int DigitCount(int v)
    {
        v = Math.Abs(v);
        if (v < 10) return 1;
        if (v < 100) return 2;
        if (v < 1000) return 3;
        if (v < 10000) return 4;
        if (v < 100000) return 5;
        if (v < 1000000) return 6;
        if (v < 10000000) return 7;
        if (v < 100000000) return 8;
        if (v < 1000000000) return 9;
        return 10;
    }

    static bool IsNumericType(Type t)
    {
        return t == typeof(int) ||
               t == typeof(uint) ||
               t == typeof(long) ||
               t == typeof(ulong) ||
               t == typeof(short) ||
               t == typeof(ushort) ||
               t == typeof(byte) ||
               t == typeof(sbyte) ||
               t == typeof(float) ||
               t == typeof(double) ||
               t == typeof(decimal);
    }
}
