using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Media;

namespace ClawdDotNet.Desktop.Controls;

/// <summary>
/// Ein Strichsymbol aus dem Entwurf — 24×24-Geometrie, gezeichnet mit der geerbten
/// Vordergrundfarbe.
///
/// <para>Warum nicht <c>PathIcon</c>: Das füllt seine Geometrie. Die Symbole des Entwurfs
/// sind Umrisse (Lucide, Strichstärke 1.5); gefüllt werden daraus schwarze Klumpen.</para>
///
/// <para>Warum nicht <c>Path</c> mit <c>Stroke</c>: Dann müsste an jeder einzelnen Stelle
/// die Farbe mitgegeben werden — und zwar die <em>richtige</em>, je nachdem ob das Symbol
/// in einer Schaltfläche, einer ausgewählten Navigationszeile oder der Statusleiste sitzt.
/// <see cref="Foreground"/> ist hier von <see cref="TextElement"/> übernommen und erbt
/// daher wie eine Textfarbe: Wer den Text einfärbt, färbt das Symbol mit.</para>
///
/// <para>Die Strichstärke wird beim Skalieren mitskaliert. Das ist keine Nachlässigkeit,
/// sondern das Verhalten von SVG: <c>stroke-width</c> zählt in Einheiten des viewBox.
/// Ein Symbol mit 1.5 in 24×24, dargestellt auf 16 px, hat genau 1 px starke Linien.</para>
/// </summary>
public sealed class StrokeIcon : Control
{
    /// <summary>Kantenlänge des Koordinatenraums aller Symbole (SVG-viewBox 0 0 24 24).</summary>
    private const double ViewBox = 24d;

    public static readonly StyledProperty<Geometry?> DataProperty =
        AvaloniaProperty.Register<StrokeIcon, Geometry?>(nameof(Data));

    /// <summary>Geerbt wie eine Textfarbe — siehe Klassenbeschreibung.</summary>
    public static readonly StyledProperty<IBrush?> ForegroundProperty =
        TextElement.ForegroundProperty.AddOwner<StrokeIcon>();

    public static readonly StyledProperty<double> StrokeThicknessProperty =
        AvaloniaProperty.Register<StrokeIcon, double>(nameof(StrokeThickness), 1.5d);

    /// <summary>Für die wenigen massiven Symbole des Entwurfs (Wiedergabe, Halt).</summary>
    public static readonly StyledProperty<bool> IsFilledProperty =
        AvaloniaProperty.Register<StrokeIcon, bool>(nameof(IsFilled));

    static StrokeIcon()
    {
        AffectsRender<StrokeIcon>(
            DataProperty, ForegroundProperty, StrokeThicknessProperty, IsFilledProperty);
        AffectsMeasure<StrokeIcon>(DataProperty);
    }

    public Geometry? Data
    {
        get => GetValue(DataProperty);
        set => SetValue(DataProperty, value);
    }

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

    public double StrokeThickness
    {
        get => GetValue(StrokeThicknessProperty);
        set => SetValue(StrokeThicknessProperty, value);
    }

    public bool IsFilled
    {
        get => GetValue(IsFilledProperty);
        set => SetValue(IsFilledProperty, value);
    }

    /// <summary>
    /// Ohne gesetzte Größe 16×16 — die Größe, in der die meisten Symbole im Entwurf stehen.
    /// Ein unbegrenzter Vorschlag würde das Symbol den ganzen Platz nehmen lassen.
    /// </summary>
    protected override Size MeasureOverride(Size availableSize)
    {
        var width = double.IsInfinity(availableSize.Width) ? 16d : Math.Min(16d, availableSize.Width);
        var height = double.IsInfinity(availableSize.Height) ? 16d : Math.Min(16d, availableSize.Height);
        return new Size(width, height);
    }

    public override void Render(DrawingContext context)
    {
        if (Data is not { } geometry || Foreground is not { } brush) return;

        var scale = Math.Min(Bounds.Width / ViewBox, Bounds.Height / ViewBox);
        if (scale <= 0) return;

        // Mittig setzen, falls das Steuerelement nicht quadratisch ist.
        var offsetX = (Bounds.Width - ViewBox * scale) / 2;
        var offsetY = (Bounds.Height - ViewBox * scale) / 2;

        using var _ = context.PushTransform(
            Matrix.CreateScale(scale, scale) * Matrix.CreateTranslation(offsetX, offsetY));

        if (IsFilled)
        {
            context.DrawGeometry(brush, null, geometry);
            return;
        }

        // Runde Enden und Verbindungen: Ohne sie verschwinden die Punkt-Symbole
        // (Pfadstücke der Länge 0.01, etwa in „Agenten-Chats") vollständig.
        var pen = new Pen(brush, StrokeThickness,
            lineCap: PenLineCap.Round, lineJoin: PenLineJoin.Round);

        context.DrawGeometry(null, pen, geometry);
    }
}
