using Avalonia;
using Avalonia.Media;
using TraceCad.Core.Geometry;

namespace TraceCad.App.Tools;

internal static class ToolDrawing
{
    public static readonly Pen PreviewPen = new(Brushes.DeepSkyBlue, 1.5);
    public static readonly Pen InvalidPen = new(Brushes.OrangeRed, 1.5);
    public static readonly Pen SnapPen = new(Brushes.LimeGreen, 1.6);
    public static readonly Pen TangentPen = new(Brushes.MediumSpringGreen, 1.4);

    public static void DrawPointMarker(DrawingContext context, ViewTransform transform, Point2 point)
    {
        var screen = transform.ModelToScreen(point);
        context.DrawEllipse(Brushes.White, new Pen(Brushes.DeepSkyBlue, 1.2), screen, 4.0, 4.0);
    }

    public static void DrawSnapMarker(DrawingContext context, ViewTransform transform, SnapResult snap)
    {
        if (snap.Kind == SnapKind.None)
        {
            return;
        }

        var screen = transform.ModelToScreen(snap.Point);
        var size = snap.Kind == SnapKind.Endpoint ? 7.0 : 5.5;
        var rect = new Rect(screen.X - size, screen.Y - size, size * 2.0, size * 2.0);
        context.DrawRectangle(null, SnapPen, rect);

        if (snap.Tangent is { Length: > GeometryConstants.Epsilon } tangent)
        {
            var direction = tangent.Normalized();
            var modelA = snap.Point - (direction * (18.0 / transform.Scale));
            var modelB = snap.Point + (direction * (18.0 / transform.Scale));
            context.DrawLine(TangentPen, transform.ModelToScreen(modelA), transform.ModelToScreen(modelB));
        }
    }

    public static void DrawCircle(DrawingContext context, ViewTransform transform, Point2 center, double radius, Pen pen)
    {
        var screen = transform.ModelToScreen(center);
        context.DrawEllipse(null, pen, screen, radius * transform.Scale, radius * transform.Scale);
    }

    public static void DrawArc(
        DrawingContext context,
        ViewTransform transform,
        Point2 center,
        double radius,
        double startAngleDeg,
        double endAngleDeg,
        bool isClockwise,
        Pen pen)
    {
        var sweep = isClockwise
            ? GeometryHelpers.ClockwiseSweepDeg(startAngleDeg, endAngleDeg)
            : GeometryHelpers.CounterClockwiseSweepDeg(startAngleDeg, endAngleDeg);

        if (sweep <= GeometryConstants.Epsilon)
        {
            return;
        }

        var start = PointAtAngle(transform, center, radius, startAngleDeg);
        var end = PointAtAngle(transform, center, radius, endAngleDeg);
        var geometry = new StreamGeometry();

        using (var stream = geometry.Open())
        {
            stream.BeginFigure(start, isFilled: false);
            stream.ArcTo(
                end,
                new Size(radius * transform.Scale, radius * transform.Scale),
                0.0,
                sweep > 180.0,
                isClockwise ? SweepDirection.CounterClockwise : SweepDirection.Clockwise);
        }

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

    private static Point PointAtAngle(ViewTransform transform, Point2 center, double radius, double angleDeg)
    {
        var radians = angleDeg * Math.PI / 180.0;
        return transform.ModelToScreen(new Point2(
            center.X + (Math.Cos(radians) * radius),
            center.Y + (Math.Sin(radians) * radius)));
    }
}
