using Avalonia;
using Avalonia.Media;
using Ehwrj.Core.Geometry;

namespace Ehwrj.App.Rendering;

public sealed class OverlayCanvas : MapCanvas
{
    public override void Render(DrawingContext context)
    {
        var bounds = new Rect(0, 0, Bounds.Width, Bounds.Height);
        var settings = OverlaySettings;
        if (!settings.ShowMiniMap && !settings.ShowSpotRadar)
        {
            return;
        }

        if (settings.ShowMiniMap)
        {
            DrawMiniMap(context, bounds);
        }

        if (settings.ShowSpotRadar)
        {
            DrawSpotRadar(context, bounds);
        }
    }

    private void DrawMiniMap(DrawingContext context, Rect bounds)
    {
        var alpha = (byte)Math.Clamp(OverlaySettings.SpotOpacity / 100.0 * 220, 0, 220);
        context.DrawRectangle(new SolidColorBrush(Color.FromArgb(120, 0, 0, 0)), null, bounds, 8, 8);

        if (Snapshot.MapImage is not null)
        {
            using (context.PushOpacity(0.82))
            {
                context.DrawImage(Snapshot.MapImage, new Rect(Snapshot.MapImage.Size), bounds);
            }
        }

        var rect = new Rect(0, 0, bounds.Width, bounds.Height);
        foreach (var obj in Snapshot.Objects)
        {
            var point = ProjectPointRaw(obj, Snapshot, rect);
            if (point is null) continue;
            if (obj.IsAircraft && obj.Mach.GetValueOrDefault() < OverlaySettings.MiniMapMinimumMach) continue;

            var color = obj.IsPlayer ? Color.FromRgb(76, 201, 167) : obj.IsAircraft ? Color.FromRgb(255, 30, 30) : Color.FromRgb(240, 220, 150);
            color = Color.FromArgb(alpha, color.R, color.G, color.B);
            var brush = new SolidColorBrush(color);
            var scale = OverlaySettings.MiniMapAircraftScale / 100.0;
            var radius = (obj.IsPlayer ? 8 : obj.IsAircraft ? 5 : 3) * scale;
            context.DrawEllipse(brush, new Pen(Brushes.Black, 1), point.Value, radius, radius);

            if (OverlaySettings.ShowMach && obj.Mach.HasValue)
            {
                var textColor = ParseColor(OverlaySettings.SpotTextColor, Colors.White);
                DrawOutlinedText(context, obj.Mach.Value.ToString("0.0"), new Point(point.Value.X + 8, point.Value.Y - 10), 13, textColor, 1, OverlaySettings.SpotFontOpacity);
            }
        }
    }

    private void DrawSpotRadar(DrawingContext context, Rect bounds)
    {
        var player = Snapshot.Player;
        if (player is null) return;

        var minSide = Math.Min(bounds.Width, bounds.Height);
        var center = new Point(
            bounds.Width / 2,
            bounds.Height / 2 + OverlaySettings.SpotVerticalOffset * minSide / 2240.0);
        var radius = minSide * 0.42 * (OverlaySettings.SpotDistance / 529.0);
        radius = Math.Clamp(radius, minSide * 0.08, minSide * 0.48);
        var radarPen = new Pen(new SolidColorBrush(Color.FromArgb(90, 255, 255, 255)), 1);
        context.DrawEllipse(null, radarPen, center, radius, radius);
        context.DrawLine(radarPen, new Point(center.X, center.Y - radius), new Point(center.X, center.Y + radius));
        context.DrawLine(radarPen, new Point(center.X - radius, center.Y), new Point(center.X + radius, center.Y));

        foreach (var target in Snapshot.Objects.Where(static o => o.IsAircraft && !o.IsPlayer))
        {
            var distance = CoordinateProjector.ApproximateDistanceKm(player, target);
            if (!double.IsFinite(distance) || distance <= 0 || distance > OverlaySettings.SpotDetectDistanceKm) continue;
            if (target.Mach.GetValueOrDefault() < OverlaySettings.SpotMinimumMach) continue;

            var dx = target.X!.Value - player.X!.Value;
            var dy = target.Y!.Value - player.Y!.Value;
            var rawDistance = Math.Sqrt(dx * dx + dy * dy);
            if (rawDistance <= double.Epsilon) continue;

            var normalizedDistance = Math.Clamp(distance / Math.Max(1, OverlaySettings.SpotDetectDistanceKm), 0, 1);
            var point = new Point(
                center.X + dx / rawDistance * normalizedDistance * radius,
                center.Y + dy / rawDistance * normalizedDistance * radius * (OverlaySettings.SpotVerticalScale / 100.0));
            var opacity = (byte)Math.Clamp(OverlaySettings.SpotOpacity / 100.0 * 255, 0, 255);
            var arrowColor = ParseColor(OverlaySettings.SpotArrowColor, Color.FromRgb(255, 30, 30));
            var brush = new SolidColorBrush(Color.FromArgb(opacity, arrowColor.R, arrowColor.G, arrowColor.B));
            DrawTriangle(context, point, 12 * OverlaySettings.SpotArrowScale / 100.0, brush, OverlaySettings.SpotOutlineWidth);

            var lineY = point.Y - 13;
            if (OverlaySettings.SpotShowDistance)
            {
                DrawOutlinedText(
                    context,
                    $"{distance:0.0} km",
                    new Point(point.X + 14, lineY),
                    OverlaySettings.DistanceFontSize,
                    ParseColor(OverlaySettings.DistanceTextColor, Color.FromRgb(255, 30, 30)),
                    OverlaySettings.DistanceOutlineWidth,
                    OverlaySettings.SpotFontOpacity);
                lineY += OverlaySettings.DistanceFontSize + 2;
            }

            if (OverlaySettings.SpotShowMach && target.Mach.HasValue)
            {
                DrawOutlinedText(
                    context,
                    $"M {target.Mach.Value:0.0}",
                    new Point(point.X + 14, lineY),
                    OverlaySettings.MachFontSize,
                    ParseColor(OverlaySettings.MachTextColor, Color.FromRgb(87, 199, 242)),
                    OverlaySettings.MachOutlineWidth,
                    OverlaySettings.SpotFontOpacity);
                lineY += OverlaySettings.MachFontSize + 2;
            }

            if (OverlaySettings.SpotShowRelativeSpeed && target.ClosureSpeed.HasValue)
            {
                DrawOutlinedText(
                    context,
                    $"{target.ClosureSpeed.Value:+0;-0;0} m/s",
                    new Point(point.X + 14, lineY),
                    OverlaySettings.RelativeFontSize,
                    ParseColor(OverlaySettings.RelativeTextColor, Color.FromRgb(25, 242, 79)),
                    OverlaySettings.RelativeOutlineWidth,
                    OverlaySettings.SpotFontOpacity);
            }
        }
    }

    private static void DrawTriangle(DrawingContext context, Point center, double size, IBrush brush, double outlineWidth)
    {
        var geometry = new StreamGeometry();
        using (var ctx = geometry.Open())
        {
            ctx.BeginFigure(new Point(center.X, center.Y - size), true);
            ctx.LineTo(new Point(center.X + size * 0.8, center.Y + size * 0.7));
            ctx.LineTo(new Point(center.X - size * 0.8, center.Y + size * 0.7));
            ctx.EndFigure(true);
        }

        var outline = outlineWidth > 0 ? new Pen(Brushes.Black, outlineWidth) : null;
        context.DrawGeometry(brush, outline, geometry);
    }
}
