using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using ytLive.Models;

namespace ytLive.Services.Compositor;

/// <summary>
/// Rasterizes the global social bar into a transparent BGRA8 strip the output
/// compositor overlays onto the master frame (top or bottom edge). Replicates the
/// preview's bar DataTemplate in code — one Path (logo) + one TextBlock (handle)
/// per entry, white on transparent, green glow — then software-renders it via
/// <c>RenderTargetBitmap</c> and converts Pbgra32 (premultiplied) to straight-alpha
/// BGRA for the compositor. WPF glue like <see cref="StaticPixelCache"/>: the
/// compositor core itself stays pure byte-math. Renders on the UI thread only;
/// the returned frame is immutable afterwards, so the frame pump may read it from
/// any thread.
/// </summary>
public static class SocialBarRenderer
{
    /// <summary>Icon size + the preview's 8px top/bottom margins.</summary>
    private const int ContentHeight = 40;

    /// <summary>Room for the green DropShadowEffect blur to bleed past the content.</summary>
    private const int GlowPad = 24;

    /// <summary>Master-frame width — the bar spans the full 1920px output.</summary>
    public const int Width = 1920;

    /// <summary>Returns the strip frame, or null when there is nothing to render.</summary>
    public static VideoFrame? Render(IEnumerable<SocialEntry>? entries)
    {
        var list = entries?.Where(e => e != null).ToList();
        if (list == null || list.Count == 0) return null;

        var height = ContentHeight + GlowPad * 2;

        var row = new StackPanel { Orientation = Orientation.Horizontal };
        foreach (var entry in list)
        {
            var item = new StackPanel
            {
                Orientation = Orientation.Horizontal,
                Margin = new Thickness(0, 0, 20, 0),
            };
            item.Children.Add(new Path
            {
                Data = Geometry.Parse(entry.LogoData),
                Fill = Brushes.White,
                Width = 24,
                Height = 24,
                Stretch = Stretch.Uniform,
                VerticalAlignment = VerticalAlignment.Center,
            });
            item.Children.Add(new TextBlock
            {
                Text = entry.Handle,
                Foreground = Brushes.White,
                FontSize = 14,
                VerticalAlignment = VerticalAlignment.Center,
                Margin = new Thickness(8, 0, 0, 0),
            });
            row.Children.Add(item);
        }

        // The glow is baked in so the output bar matches the preview's green halo.
        var container = new Grid
        {
            Width = Width,
            Height = height,
            Background = Brushes.Transparent,
            Effect = new DropShadowEffect { Color = Color.FromRgb(0x2e, 0xcc, 0x71), BlurRadius = 18, ShadowDepth = 0, Opacity = 0.9 },
        };
        var centered = new Grid { HorizontalAlignment = HorizontalAlignment.Center, Margin = new Thickness(0, GlowPad, 0, 0) };
        centered.Children.Add(row);
        container.Children.Add(centered);

        container.Measure(new Size(Width, height));
        container.Arrange(new Rect(0, 0, Width, height));

        var bitmap = new RenderTargetBitmap(Width, height, 96, 96, PixelFormats.Pbgra32);
        bitmap.Render(container);

        var pixels = new byte[Width * height * 4];
        bitmap.CopyPixels(pixels, Width * 4, 0);

        // Pbgra32 is premultiplied — unpremultiply so the compositor's straight-alpha
        // source-over blend doesn't darken the logo edges with a halo.
        for (var i = 0; i < pixels.Length; i += 4)
        {
            var a = pixels[i + 3];
            if (a == 0 || a == 255) continue;
            pixels[i] = (byte)(pixels[i] * 255 / a);
            pixels[i + 1] = (byte)(pixels[i + 1] * 255 / a);
            pixels[i + 2] = (byte)(pixels[i + 2] * 255 / a);
        }

        return new VideoFrame(Width, height, pixels);
    }
}
