using System.Collections.Specialized;
using Avalonia.Media;
using Avalonia.Media.Immutable;

namespace AtomUI.Media;

public static class PenUtils
{
   /// <summary>
   /// Smart reuse and update pen properties.
   /// </summary>
   /// <param name="pen">Old pen to modify.</param>
   /// <param name="brush">The brush used to draw.</param>
   /// <param name="thickness">The stroke thickness.</param>
   /// <param name="strokeDashArray">The stroke dask array.</param>
   /// <param name="strokeDaskOffset">The stroke dask offset.</param>
   /// <param name="lineCap">The line cap.</param>
   /// <param name="lineJoin">The line join.</param>
   /// <param name="miterLimit">The miter limit.</param>
   /// <returns>If a new instance was created and visual invalidation required.</returns>
   internal static bool TryModifyOrCreate(ref IPen? pen,
                                          IBrush? brush,
                                          double thickness,
                                          IList<double>? strokeDashArray = null,
                                          double strokeDaskOffset = 0.0,
                                          PenLineCap lineCap = PenLineCap.Flat,
                                          PenLineJoin lineJoin = PenLineJoin.Miter,
                                          double miterLimit = 10.0)
    {
        var previousPen = pen;
        if (brush is null)
        {
            pen = null;
            return previousPen is not null;
        }

        IDashStyle? dashStyle = null;
        if (strokeDashArray is { Count: > 0 })
        {
            // strokeDashArray can be IList (instead of AvaloniaList) in future
            // So, if it supports notification - create a mutable DashStyle
            dashStyle = strokeDashArray is INotifyCollectionChanged
                ? new DashStyle(strokeDashArray, strokeDaskOffset)
                : new ImmutableDashStyle(strokeDashArray, strokeDaskOffset);
        }

        if (brush is IImmutableBrush immutableBrush && dashStyle is null or ImmutableDashStyle)
        {
            pen = new ImmutablePen(
                immutableBrush,
                thickness,
                (ImmutableDashStyle?)dashStyle,
                lineCap,
                lineJoin,
                miterLimit);

            return true;
        }

        var mutablePen = previousPen as Pen ?? new Pen();
        mutablePen.Brush      = brush;
        mutablePen.Thickness  = thickness;
        mutablePen.LineCap    = lineCap;
        mutablePen.LineJoin   = lineJoin;
        mutablePen.DashStyle  = dashStyle;
        mutablePen.MiterLimit = miterLimit;

        pen = mutablePen;
        return !Equals(previousPen, pen);
    }
}