using Xunit;
using ytLive.Models;
using ytLive.ViewModels;

namespace ytLive.Tests;

/// <summary>
/// The backdrop is a permanent, non-deletable bottom layer holding live
/// desktop/game capture, and it exists only in the canonical Live scene (see
/// <see cref="SceneCatalog"/>). Every backdrop-enabled scene
/// (<see cref="Scene.HasBackdrop"/>) is healed to have exactly one, inserted
/// first; it is never reorderable or removable by the UI. Scenes without the
/// flag never get one.
/// </summary>
public class BackdropTests
{
    [Fact]
    public void EnsureBackdrop_OnEmptyScene_InsertsFullFrameBackdrop()
    {
        var scene = new Scene { Name = "S", HasBackdrop = true };

        var backdrop = MainViewModel.EnsureBackdrop(scene);

        Assert.NotNull(backdrop);
        Assert.Single(scene.Elements);
        Assert.Same(backdrop, scene.Elements[0]);
        Assert.True(backdrop.IsBackdrop);
        Assert.True(backdrop.IsEnabled);
        Assert.Equal(SourceType.DisplayCapture, backdrop.Type);
        Assert.Equal(0, backdrop.X);
        Assert.Equal(0, backdrop.Y);
        Assert.Equal(1920, backdrop.Width);
        Assert.Equal(1080, backdrop.Height);
    }

    [Fact]
    public void EnsureBackdrop_ExistingBackdrop_IsIdempotent()
    {
        var scene = new Scene { Name = "S", HasBackdrop = true };
        var first = MainViewModel.EnsureBackdrop(scene);
        var second = MainViewModel.EnsureBackdrop(scene);

        Assert.Same(first, second);
        Assert.Single(scene.Elements);
    }

    [Fact]
    public void EnsureBackdrop_HealsMissingBackdropAtIndexZero()
    {
        var scene = new Scene { Name = "S", HasBackdrop = true };
        var image = new Source { Name = "Logo", Type = SourceType.Image };
        scene.Elements.Add(image);

        MainViewModel.EnsureBackdrop(scene);

        Assert.Equal(2, scene.Elements.Count);
        Assert.True(((Source)scene.Elements[0]).IsBackdrop);
        Assert.Same(image, scene.Elements[1]);
    }

    [Fact]
    public void EnsureBackdrop_SceneWithoutHasBackdrop_ReturnsNullAndInsertsNothing()
    {
        var scene = new Scene { Name = "Ending", HasBackdrop = false };

        var backdrop = MainViewModel.EnsureBackdrop(scene);

        Assert.Null(backdrop);
        Assert.Empty(scene.Elements);
    }

    [Theory]
    [InlineData(SourceType.DisplayCapture, true)]
    [InlineData(SourceType.WindowCapture, true)]
    [InlineData(SourceType.Background, false)]
    [InlineData(SourceType.Image, false)]
    [InlineData(SourceType.TextOverlay, false)]
    public void Source_IsLiveCapture_OnlyForDisplayAndWindow(SourceType type, bool expected)
    {
        Assert.Equal(expected, new Source { Type = type }.IsLiveCapture);
    }

    [Fact]
    public void Source_DisplaySource_IsVideoImageSource_WhenLiveCapture()
    {
        var source = new Source { Type = SourceType.DisplayCapture };
        var bitmap = new System.Windows.Media.Imaging.WriteableBitmap(
            2, 2, 96, 96, System.Windows.Media.PixelFormats.Bgra32, null);
        source.VideoImageSource = bitmap;

        Assert.Same(bitmap, source.DisplaySource);
    }

    [Fact]
    public void Source_DisplaySource_IsImageSource_WhenNotLiveCapture()
    {
        var source = new Source { Type = SourceType.Background };
        var bitmap = new System.Windows.Media.Imaging.WriteableBitmap(
            2, 2, 96, 96, System.Windows.Media.PixelFormats.Bgra32, null);
        source.VideoImageSource = bitmap;

        Assert.NotSame(bitmap, source.DisplaySource);
        Assert.Null(source.DisplaySource);
    }

    [Fact]
    public void Source_TypeChange_RaisesDisplaySource()
    {
        var source = new Source { Type = SourceType.Image };
        var raised = new List<string>();
        source.PropertyChanged += (_, e) => raised.Add(e.PropertyName ?? string.Empty);

        source.Type = SourceType.DisplayCapture;

        Assert.Contains(nameof(Source.IsLiveCapture), raised);
        Assert.Contains(nameof(Source.DisplaySource), raised);
    }
}
