using IWS5.Server.Enums;
using Syncfusion.Drawing;
using Syncfusion.Pdf;
using Syncfusion.Pdf.Graphics;

namespace IWS5.Server.Utils.Converter.PdfConverter;

public class ImageFileToPdfConverter : IFileConverter
{
    private static readonly HashSet<string> Extensions = new(StringComparer.OrdinalIgnoreCase)
    {
        nameof(ConvertibleFileTypes.jpeg).ToLowerInvariant(),
        nameof(ConvertibleFileTypes.jpg).ToLowerInvariant(),
        nameof(ConvertibleFileTypes.png).ToLowerInvariant()
    };

    public bool CanConvert(string sourceFileExtension, string targetFileExtension) => Extensions.Contains(sourceFileExtension) && 
        string.Equals(targetFileExtension, nameof(ConvertibleFileTypes.pdf), StringComparison.OrdinalIgnoreCase);

    public async Task<byte[]> ConvertAsync(byte[] inputFile)
    {
        using var imageStream = new MemoryStream(inputFile);
        using var document = new PdfDocument();

        PdfImage image = PdfImage.FromStream(imageStream);
        SizeF imageSize = image.PhysicalDimension;

        // Scale large images maintaining aspect ratio
        SizeF pageSize = GetScaledPageSize(imageSize, 2500f);

        document.PageSettings.Margins.All = 0;
        document.PageSettings.Width = pageSize.Width;
        document.PageSettings.Height = pageSize.Height;

        PdfPage page = document.Pages.Add();
        page.Graphics.DrawImage(image, new RectangleF(PointF.Empty, pageSize));

        using var pdfStream = new MemoryStream();
        document.Save(pdfStream);
        document.Close(true);

        return await Task.FromResult(pdfStream.ToArray());
    }

    /// <summary>
    /// Calculates a scaled PDF page size based on a maximum allowed dimension,
    /// preserving the original aspect ratio.
    /// </summary>
    private SizeF GetScaledPageSize(SizeF originalSize, float maxDimension)
    {
        float width = originalSize.Width;
        float height = originalSize.Height;

        if (width <= maxDimension && height <= maxDimension)
        {
            return originalSize;
        }

        float scalingFactor = maxDimension / Math.Max(width, height);
        return new SizeF(width * scalingFactor, height * scalingFactor);
    }
}

