using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Data.Sqlite;
using Xunit;
using ytLive.Models;
using ytLive.ViewModels;
namespace ytLive.Tests;
///
/// TASK 47 Good Dog (take three, 2026-09-26): the alert box's frame must be
/// DRAWN by the preview pane. The 14:26 and 14:28 live runs on build 90 proved
/// everything up to the last hop: Alert preview: frame=680x200 a255 and
/// Output resolver: frame 680x200 playing=True every second for the whole
/// clip — a real, opaque, correctly-sized frame (the shipped llama asset decodes
/// bright, 1280x720 h264) handed to the canvas — and the box stayed blank.
/// Root cause: the preview's per-element Image only becomes Visible for
/// IsImageSource / IsChatBox / IsWebSource / IsWebcam, so an AlertBox's Image
/// stayed Collapsed and the bound frame was never rendered.
///
[Collection("RealApp")]
public sealed class AlertBoxPreviewVisibilityTests
{
private readonly RealAppHost _app;
public AlertBoxPreviewVisibilityTests(RealAppHost app) => _app = app;
[Fact]
public void AlertBox_HandedAFrame_IsDrawnInThePreviewPane()
{
_app.Run(Run);
}
private void Run()
{
var tempDb = Path.Combine(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 box = new Source
{
Type = SourceType.AlertBox,
Name = "Stream Alerts",
X = 100,
Y = 100,
Width = 320,
Height = 180,
};
vm.StagedScene!.Elements.Add(box);
vm.SelectedElement = box;
// Exactly what the layer writes onto the source every tick while a clip
// plays: a real, opaque, box-sized frame.
box.VideoImageSource = SolidFrame(320, 180);
window.UpdateLayout();
var pane = (UserControl)window.FindName("PreviewPane")!;
var image = FindImageShowing(pane, box.VideoImageSource);
Assert.True(image != null,
"the preview pane never bound the alert box's frame to an Image");
Assert.Equal(Visibility.Visible, image!.Visibility);
Assert.True(image.IsVisible,
"the alert box's Image is Collapsed, so the frame is never rendered");
}
finally
{
window.Close();
MainViewModel.LayoutPathOverride = null;
SqliteConnection.ClearAllPools();
try { File.Delete(tempDb); } catch { /* best-effort cleanup */ }
}
}
private static WriteableBitmap SolidFrame(int w, int h)
{
var bitmap = new WriteableBitmap(w, h, 96, 96, PixelFormats.Bgra32, null);
var pixels = new byte[w * h * 4];
for (var i = 0; i < pixels.Length; i += 4)
{
pixels[i] = 40; // B
pixels[i + 1] = 90; // G
pixels[i + 2] = 200; // R
pixels[i + 3] = 255; // opaque
}
bitmap.WritePixels(new Int32Rect(0, 0, w, h), pixels, w * 4, 0);
return bitmap;
}
private static Image? FindImageShowing(DependencyObject parent, ImageSource? source)
=> Walk(parent, e => e is Image i && ReferenceEquals(i.Source, source)) as Image;
private static DependencyObject? Walk(DependencyObject parent, Func 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;
}
}