using System.IO;
using SkiaSharp;

namespace Jellyfin.Plugin.SRFPlay.Utilities;

/// <summary>
/// Generates placeholder images for content without thumbnails.
/// </summary>
public static class PlaceholderImageGenerator
{
    private const int Width = 640;
    private const int Height = 360; // 16:9 aspect ratio

    /// <summary>
    /// Generates a placeholder image with the given text centered.
    /// </summary>
    /// <param name="text">The text to display (typically channel/show name).</param>
    /// <returns>A memory stream containing the PNG image.</returns>
    public static MemoryStream GeneratePlaceholder(string text)
    {
        using var surface = SKSurface.Create(new SKImageInfo(Width, Height));
        var canvas = surface.Canvas;

        // Dark gradient background
        using var backgroundPaint = new SKPaint();
        using var shader = SKShader.CreateLinearGradient(
            new SKPoint(0, 0),
            new SKPoint(Width, Height),
            new[] { new SKColor(45, 45, 48), new SKColor(28, 28, 30) },
            null,
            SKShaderTileMode.Clamp);
        backgroundPaint.Shader = shader;
        canvas.DrawRect(0, 0, Width, Height, backgroundPaint);

        // Text
        using var textPaint = new SKPaint
        {
            Color = SKColors.White,
            IsAntialias = true,
            TextAlign = SKTextAlign.Center,
            Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold)
        };

        // Calculate font size and wrap text if needed
        float fontSize = 48;
        textPaint.TextSize = fontSize;
        var maxWidth = Width * 0.85f;
        var maxHeight = Height * 0.8f;

        var lines = WrapText(text, textPaint, maxWidth, maxHeight, ref fontSize);

        // Draw each line centered
        var lineHeight = fontSize * 1.2f;
        var totalHeight = lines.Count * lineHeight;
        var startY = ((Height - totalHeight) / 2) + fontSize;

        foreach (var line in lines)
        {
            canvas.DrawText(line, Width / 2, startY, textPaint);
            startY += lineHeight;
        }

        // Encode to PNG
        using var image = surface.Snapshot();
        using var data = image.Encode(SKEncodedImageFormat.Png, 100);

        var stream = new MemoryStream();
        data.SaveTo(stream);
        stream.Position = 0;
        return stream;
    }

    /// <summary>
    /// Wraps text to fit within the specified width and height constraints.
    /// </summary>
    /// <param name="text">The text to wrap.</param>
    /// <param name="paint">The paint to use for measuring.</param>
    /// <param name="maxWidth">Maximum width for each line.</param>
    /// <param name="maxHeight">Maximum total height.</param>
    /// <param name="fontSize">Font size (will be adjusted if needed).</param>
    /// <returns>List of text lines.</returns>
    private static System.Collections.Generic.List<string> WrapText(
        string text,
        SKPaint paint,
        float maxWidth,
        float maxHeight,
        ref float fontSize)
    {
        const float minFontSize = 20;
        var words = text.Split(' ');
        var lines = new System.Collections.Generic.List<string>();

        while (fontSize >= minFontSize)
        {
            paint.TextSize = fontSize;
            lines.Clear();

            var currentLine = string.Empty;
            foreach (var word in words)
            {
                var testLine = string.IsNullOrEmpty(currentLine) ? word : $"{currentLine} {word}";
                var testWidth = paint.MeasureText(testLine);

                if (testWidth > maxWidth && !string.IsNullOrEmpty(currentLine))
                {
                    lines.Add(currentLine);
                    currentLine = word;
                }
                else
                {
                    currentLine = testLine;
                }
            }

            if (!string.IsNullOrEmpty(currentLine))
            {
                lines.Add(currentLine);
            }

            // Check if total height fits
            var lineHeight = fontSize * 1.2f;
            var totalHeight = lines.Count * lineHeight;

            if (totalHeight <= maxHeight)
            {
                break;
            }

            // Reduce font size and try again
            fontSize -= 2;
        }

        // If still doesn't fit, just return what we have
        if (lines.Count == 0)
        {
            lines.Add(text);
        }

        return lines;
    }
}
