using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Svg;
using System;
using System.Numerics;
using Windows.Foundation;
using Windows.UI;

namespace Sonex.Client.Controls.SceneCanvas;

public sealed class SceneCanvasSvgObject : SceneCanvasObject
{
    public const string DefaultSvgCode =
        """
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
          <rect x="8" y="8" width="84" height="84" rx="12" fill="#7ab6ff" stroke="#2b5d9b" stroke-width="6"/>
          <circle cx="50" cy="50" r="18" fill="#ffffff"/>
        </svg>
        """;

    private string _svgCode = DefaultSvgCode;
    private CanvasSvgDocument? _cachedDocument;
    private ICanvasResourceCreator? _cachedResourceCreator;
    private string _cachedSvgCode = string.Empty;

    public SceneCanvasSvgObject(Rect boundsMeters, string? svgCode = null)
        : base(boundsMeters)
    {
        CanMove = true;
        CanResize = true;
        CanRotate = true;
        SvgCode = svgCode ?? DefaultSvgCode;
    }

    public string SvgCode
    {
        get => _svgCode;
        set
        {
            var normalized = NormalizeSvgCode(value);
            if (string.Equals(_svgCode, normalized, StringComparison.Ordinal))
            {
                return;
            }

            _svgCode = normalized;
            ResetSvgCache();
        }
    }

    public override SceneCanvasObject Clone()
    {
        var clone = new SceneCanvasSvgObject(BoundsMeters, SvgCode);
        CopyBasePropertiesTo(clone);
        return clone;
    }

    public override void OnDraw(SceneCanvasDrawContext context)
    {
        var width = (float)BoundsMeters.Width;
        var height = (float)BoundsMeters.Height;
        if (width <= 0f || height <= 0f)
        {
            return;
        }

        var drawingSession = context.DrawingSession;
        var x = (float)BoundsMeters.X;
        var y = (float)BoundsMeters.Y;

        var previousTransform = drawingSession.Transform;
        if (Math.Abs(RotationRadians) > 0.0001d)
        {
            var center = new Vector2(
                (float)(BoundsMeters.X + (BoundsMeters.Width * 0.5d)),
                (float)(BoundsMeters.Y + (BoundsMeters.Height * 0.5d)));

            var localRotation = Matrix3x2.CreateRotation((float)RotationRadians, center);
            drawingSession.Transform = localRotation * previousTransform;
        }

        if (TryEnsureSvgDocument(drawingSession) && _cachedDocument != null)
        {
            drawingSession.DrawSvg(_cachedDocument, new Size(width, height), x, y);
        }
        else
        {
            // Invalid SVG input fallback: visible placeholder with clear error cue.
            var fallbackFill = Color.FromArgb(64, 210, 35, 35);
            var fallbackStroke = Color.FromArgb(255, 210, 35, 35);
            var stroke = MathF.Max(0.02f, 1f / context.ZoomPixelsPerMeter);
            drawingSession.FillRectangle(x, y, width, height, fallbackFill);
            drawingSession.DrawRectangle(x, y, width, height, fallbackStroke, stroke);
            drawingSession.DrawLine(x, y, x + width, y + height, fallbackStroke, stroke);
            drawingSession.DrawLine(x + width, y, x, y + height, fallbackStroke, stroke);
        }

        if (!previousTransform.Equals(drawingSession.Transform))
        {
            drawingSession.Transform = previousTransform;
        }
    }

    private bool TryEnsureSvgDocument(ICanvasResourceCreator resourceCreator)
    {
        if (ReferenceEquals(_cachedResourceCreator, resourceCreator)
            && string.Equals(_cachedSvgCode, _svgCode, StringComparison.Ordinal))
        {
            return _cachedDocument != null;
        }

        _cachedDocument?.Dispose();
        _cachedDocument = null;

        _cachedResourceCreator = resourceCreator;
        _cachedSvgCode = _svgCode;

        try
        {
            if (!CanvasSvgDocument.IsSupported(resourceCreator.Device))
            {
                return false;
            }

            _cachedDocument = CanvasSvgDocument.LoadFromXml(resourceCreator, _svgCode);
            return _cachedDocument != null;
        }
        catch
        {
            _cachedDocument = null;
            return false;
        }
    }

    private static string NormalizeSvgCode(string? svgCode)
    {
        if (string.IsNullOrWhiteSpace(svgCode))
        {
            return DefaultSvgCode;
        }

        return svgCode.Trim();
    }

    private void ResetSvgCache()
    {
        _cachedDocument?.Dispose();
        _cachedDocument = null;
        _cachedResourceCreator = null;
        _cachedSvgCode = string.Empty;
    }
}

