using IWS5.Importer.Abstractions.FileSystem;
using IWS5.Importer.Abstractions.Enums;
using Syncfusion.Drawing;
using Syncfusion.Pdf;
using Syncfusion.Pdf.Graphics;

namespace IWS5.Importer.Worker.Conversion;

public class ImageFileConverter : IFileConverter
{
    private static readonly HashSet<string> Extensions = new(StringComparer.OrdinalIgnoreCase)
    {
        SupportedExtension.Jpeg.ToString().ToLowerInvariant(),
        SupportedExtension.Jpg.ToString().ToLowerInvariant(),
        SupportedExtension.Png.ToString().ToLowerInvariant()
    };

    public bool CanConvert(string extension) => Extensions.Contains(extension);

    public async Task ConvertAsync(string inputPath, string outputPath, CancellationToken cancellationToken)
    {
        using FileStream imageStream = new(inputPath, FileMode.Open, FileAccess.Read);
        using PdfDocument document = new();

        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 FileStream pdfStream = new(outputPath, FileMode.Create, FileAccess.Write);
        document.Save(pdfStream);
        document.Close(true);

        await Task.CompletedTask;
    }

    /// <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);
    }
}