using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace NexusShell.Controls;

public sealed class NexusSparklineControl : Canvas
{
    public static readonly DependencyProperty ValuesProperty =
        DependencyProperty.Register(
            nameof(Values),
            typeof(IEnumerable<double>),
            typeof(NexusSparklineControl),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, OnValuesChanged));

    public static readonly DependencyProperty StrokeBrushProperty =
        DependencyProperty.Register(
            nameof(StrokeBrush),
            typeof(Brush),
            typeof(NexusSparklineControl),
            new FrameworkPropertyMetadata(new SolidColorBrush(Color.FromRgb(0, 217, 255)), FrameworkPropertyMetadataOptions.AffectsRender));

    private readonly Polyline _line = new()
    {
        StrokeThickness = 2,
        StrokeLineJoin = PenLineJoin.Round,
        Fill = Brushes.Transparent,
    };

    private INotifyCollectionChanged? _collectionSubscription;

    public NexusSparklineControl()
    {
        ClipToBounds = true;
        Loaded += (_, _) => Rebuild();
        SizeChanged += (_, _) => Rebuild();
        Children.Add(_line);
    }

    public IEnumerable<double>? Values
    {
        get => (IEnumerable<double>?)GetValue(ValuesProperty);
        set => SetValue(ValuesProperty, value);
    }

    public Brush StrokeBrush
    {
        get => (Brush)GetValue(StrokeBrushProperty);
        set => SetValue(StrokeBrushProperty, value);
    }

    private static void OnValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not NexusSparklineControl control)
        {
            return;
        }

        if (control._collectionSubscription is not null)
        {
            control._collectionSubscription.CollectionChanged -= control.OnCollectionChanged;
            control._collectionSubscription = null;
        }

        if (e.NewValue is INotifyCollectionChanged collection)
        {
            control._collectionSubscription = collection;
            collection.CollectionChanged += control.OnCollectionChanged;
        }

        control.Rebuild();
    }

    private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) => Rebuild();

    private void Rebuild()
    {
        _line.Stroke = StrokeBrush;
        _line.Points.Clear();

        var values = Values?.ToList() ?? [];
        if (values.Count == 0 || ActualWidth <= 0 || ActualHeight <= 0)
        {
            return;
        }

        var stepX = ActualWidth / Math.Max(values.Count - 1, 1);
        for (var i = 0; i < values.Count; i++)
        {
            var y = ActualHeight - (Math.Clamp(values[i], 0, 100) / 100d * ActualHeight);
            _line.Points.Add(new Point(i * stepX, y));
        }
    }
}
