using System.Globalization;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;

namespace NexusShell.Controls;

public sealed class LetterSpacedTextBlock : FrameworkElement
{
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(nameof(Text), typeof(string), typeof(LetterSpacedTextBlock),
            new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsRender));

    public static readonly DependencyProperty LetterSpacingProperty =
        DependencyProperty.Register(nameof(LetterSpacing), typeof(double), typeof(LetterSpacedTextBlock),
            new FrameworkPropertyMetadata(10d, FrameworkPropertyMetadataOptions.AffectsRender));

    public static readonly DependencyProperty ForegroundProperty =
        DependencyProperty.Register(nameof(Foreground), typeof(Brush), typeof(LetterSpacedTextBlock),
            new FrameworkPropertyMetadata(Brushes.White, FrameworkPropertyMetadataOptions.AffectsRender));

    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }

    public double LetterSpacing
    {
        get => (double)GetValue(LetterSpacingProperty);
        set => SetValue(LetterSpacingProperty, value);
    }

    public Brush Foreground
    {
        get => (Brush)GetValue(ForegroundProperty);
        set => SetValue(ForegroundProperty, value);
    }

    protected override Size MeasureOverride(Size availableSize) => MeasureText();

    protected override void OnRender(DrawingContext drawingContext)
    {
        if (string.IsNullOrEmpty(Text))
        {
            return;
        }

        var dpi = VisualTreeHelper.GetDpi(this).PixelsPerDip;
        var typeface = CreateTypeface();
        var brush = Foreground;
        double x = 0;

        foreach (var ch in Text)
        {
            var formatted = CreateFormattedText(ch.ToString(), typeface, brush, dpi);
            drawingContext.DrawText(formatted, new Point(x, 0));
            x += formatted.Width + LetterSpacing;
        }
    }

    private Typeface CreateTypeface() =>
        new(
            TextElement.GetFontFamily(this),
            FontStyles.Normal,
            TextElement.GetFontWeight(this),
            FontStretches.Normal);

    private FormattedText CreateFormattedText(string text, Typeface typeface, Brush brush, double dpi) =>
        new(
            text,
            CultureInfo.CurrentUICulture,
            FlowDirection.LeftToRight,
            typeface,
            TextElement.GetFontSize(this),
            brush,
            dpi);

    private Size MeasureText()
    {
        if (string.IsNullOrEmpty(Text))
        {
            return Size.Empty;
        }

        var dpi = VisualTreeHelper.GetDpi(this).PixelsPerDip;
        var typeface = CreateTypeface();
        double width = 0;
        var maxHeight = 0d;
        var chars = Text.Length;

        for (var i = 0; i < chars; i++)
        {
            var formatted = CreateFormattedText(Text[i].ToString(), typeface, Foreground, dpi);
            width += formatted.Width;
            if (i < chars - 1)
            {
                width += LetterSpacing;
            }

            maxHeight = Math.Max(maxHeight, formatted.Height);
        }

        return new Size(width, maxHeight);
    }
}
