using Avalonia.Input;
using Avalonia.Media;
using TraceCad.Core.Commands;
using TraceCad.Core.Geometry;
using TraceCad.Core.Model;

namespace TraceCad.App.Tools;

public sealed class ParallelDistanceTool : ISketchTool
{
    private LineEntity? _first;

    public string Name => "Line Distance";

    public string Prompt => _first is null
        ? "Line Distance: choose first parallel line"
        : "Line Distance: choose second parallel line";

    public void PointerDown(ToolContext context, Point2 modelPoint)
    {
        var hit = context.HitTest(modelPoint, 10.0);
        if (_first is null)
        {
            if (hit is not LineEntity line)
            {
                context.SetStatus("Line Distance: choose a line");
                return;
            }

            _first = line;
            context.SetSelected(line);
            context.SetStatus(Prompt);
            context.Invalidate();
            return;
        }

        if (hit is not LineEntity second || hit.Id == _first.Id)
        {
            context.SetStatus("Line Distance: choose a second line");
            return;
        }

        if (!ConstraintGeometry.TryMeasureParallelDistance(_first, second, out var distance))
        {
            context.SetStatus("Line Distance: selected lines are not parallel");
            return;
        }

        var measurement = new SketchConstraint(
            Guid.NewGuid(),
            ConstraintType.Distance,
            new[] { _first.Id, second.Id },
            distance);
        context.Commands.Execute(
            context.Document,
            new ConstraintEditCommand(Array.Empty<EntityReplacement>(), measurement));
        context.SetStatus($"Line Distance: {Math.Abs(distance):0.###} mm");
        _first = null;
        context.Invalidate();
    }

    public void PointerMove(ToolContext context, Point2 modelPoint)
    {
    }

    public void PointerUp(ToolContext context, Point2 modelPoint)
    {
    }

    public void KeyDown(ToolContext context, Key key)
    {
    }

    public void Cancel(ToolContext context)
    {
        _first = null;
        context.SetStatus(Prompt);
        context.Invalidate();
    }

    public void RenderOverlay(DrawingContext context, ToolRenderContext renderContext)
    {
        if (_first is null)
        {
            return;
        }

        context.DrawLine(
            ToolDrawing.TangentPen,
            renderContext.Transform.ModelToScreen(_first.Start),
            renderContext.Transform.ModelToScreen(_first.End));
    }
}
