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 ParallelConstraintTool : ISketchTool
{
    private LineEntity? _reference;

    public string Name => "Parallel";

    public string Prompt => _reference is null
        ? "Parallel: choose reference line"
        : "Parallel: choose line to make parallel";

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

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

        if (hit is not LineEntity target || hit.Id == _reference.Id)
        {
            context.SetStatus("Parallel: choose a second line");
            return;
        }

        if (!ConstraintGeometry.TryMakeParallel(_reference, target, out var replacement))
        {
            context.SetStatus("Parallel: selected line has invalid length");
            return;
        }

        var constraint = new SketchConstraint(
            Guid.NewGuid(),
            ConstraintType.Parallel,
            new[] { _reference.Id, target.Id });
        context.Commands.Execute(
            context.Document,
            new ConstraintEditCommand(
                new[] { new EntityReplacement(target, replacement) },
                constraint));
        context.SetSelected(replacement);
        context.SetStatus("Parallel constraint applied");
        _reference = 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)
    {
        _reference = null;
        context.SetStatus(Prompt);
        context.Invalidate();
    }

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

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