using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using Microsoft.Data.Sqlite;
using Xunit;
using ytLive.Models;
using ytLive.ViewModels;

namespace ytLive.Tests;

/// <summary>
/// Reproduces the real MainWindow preview to check the round-clip corner
/// handle: whether a click at the corner actually stays inside the preview
/// (doesn't fall through and deselect the source) and whether the round clip
/// renders as a circle rather than an oval.
/// </summary>
[Collection("RealApp")]
public sealed class RoundClipInteractionTests
{
    private readonly RealAppHost _app;

    public RoundClipInteractionTests(RealAppHost app)
    {
        _app = app;
    }

    [Fact]
    public void Round_Clip_Corner_Is_Grabbable_And_Shape_Is_Circle()
    {
        _app.Run(Run);
    }

    private void Run()
    {
        // Never let the real MainWindow read/write the user's actual layout DB —
        // Shutdown() saves the layout, which would persist these test sources
        // over the real ones. Point it at a throwaway temp DB instead.
        var tempDb = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"ytLlive-test-{Guid.NewGuid():N}.db");
        MainViewModel.LayoutPathOverride = tempDb;
        var window = new MainWindow();
        var vm = (MainViewModel)window.DataContext;
        try
        {
            window.Show();
            window.UpdateLayout();

            var scene = vm.ActiveScene!;
            var webcam = new WebcamSceneConfig
            {
                WebcamId = "test-camera",
                Name = "Webcam",
                X = 1408,
                Y = 778,
                Width = 480,
                Height = 270,
            };
            scene.Elements.Add(webcam);
            vm.SelectedElement = webcam;
            window.UpdateLayout();

            var previewGrid = (Grid)window.FindName("PreviewGrid")!;
            var canvasGrid = (Grid)window.FindName("CanvasGrid")!;
            var toWindow = canvasGrid.TransformToVisual(window);

            var corner = new Point(webcam.X + webcam.Width, webcam.Y + webcam.Height);

            foreach (var shape in new[] { ClipShape.Traditional, ClipShape.Round })
            {
                webcam.ClipShape = shape;
                window.UpdateLayout();

                var cornerInWindow = toWindow.Transform(corner);

                // A click on the corner must land inside the preview (descendant
                // of PreviewGrid); otherwise Window_PreviewMouseLeftButtonDown
                // deselects the source and the handle can never be grabbed.
                var hit = VisualTreeHelper.HitTest(window, cornerInWindow);
                var grabbable = hit != null && IsDescendantOf(hit.VisualHit, previewGrid);

                Assert.True(grabbable,
                    $"{shape}: corner click fell through to '{hit?.VisualHit.GetType().Name ?? "null"}' " +
                    "so the source gets deselected before the resize handler runs");
            }

            // The round clip must render as a circle (square bounding box), not an oval.
            webcam.ClipShape = ClipShape.Round;
            window.UpdateLayout();
            var clip = FindRoundClip(window);
            Assert.NotNull(clip);
            var geometry = Assert.IsType<EllipseGeometry>(clip!.Clip);
            Assert.Equal(0.5, geometry.Center.X, 1.0);
            Assert.Equal(0.5, geometry.Center.Y, 1.0);
            Assert.Equal(0.5, geometry.RadiusX, 1.0);
            Assert.Equal(0.5, geometry.RadiusY, 1.0);
            Assert.Equal(clip.ActualWidth, clip.ActualHeight, 1.0);
        }
        finally
        {
            window.Close();
            MainViewModel.LayoutPathOverride = null;
            SqliteConnection.ClearAllPools();
            try { System.IO.File.Delete(tempDb); } catch { /* best-effort cleanup */ }
        }
    }

    private static Image? FindRoundClip(Window window)
    {
        return Walk(window, element => element is Image i && i.IsVisible && i.Clip is EllipseGeometry) as Image;
    }

    private static DependencyObject? Walk(DependencyObject parent, Func<DependencyObject, bool> predicate)
    {
        for (var i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);
            if (predicate(child)) return child;
            var found = Walk(child, predicate);
            if (found != null) return found;
        }
        return null;
    }

    private static bool IsDescendantOf(DependencyObject? child, DependencyObject ancestor)
    {
        while (child != null && !ReferenceEquals(child, ancestor))
            child = VisualTreeHelper.GetParent(child);
        return child != null;
    }
}
