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

namespace IWS5.Server.Utils.Converter.PdfConverter;

public class TiffFileToPdfConverter : IFileConverter
{
    private static readonly HashSet<string> Extensions = new(StringComparer.OrdinalIgnoreCase)
    {
        nameof(ConvertibleFileTypes.tif).ToLowerInvariant(),
        nameof(ConvertibleFileTypes.tiff).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 tiffStream = new MemoryStream(inputFile);
        using var document = new PdfDocument();
        
        var tiffImage = new PdfTiffImage(tiffStream);
        int frameCount = tiffImage.FrameCount;

        for (int i = 0; i < frameCount; i++)
        {
            PdfPage page = document.Pages.Add();
            SizeF pageSize = page.GetClientSize();
            tiffImage.ActiveFrame = i;

            // Scale the image to fit the page while maintaining aspect ratio
            SizeF imageSize = new SizeF(tiffImage.Width, tiffImage.Height);
            SizeF scaledSize = GetScaledSize(imageSize, pageSize);
            
            // Center the image on the page
            float x = (pageSize.Width - scaledSize.Width) / 2;
            float y = (pageSize.Height - scaledSize.Height) / 2;
            
            page.Graphics.DrawImage(tiffImage, new RectangleF(x, y, scaledSize.Width, scaledSize.Height));
        }

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

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

    /// <summary>
    /// Calculates a scaled size that fits within the target size while maintaining aspect ratio.
    /// </summary>
    private static SizeF GetScaledSize(SizeF originalSize, SizeF targetSize)
    {
        if (originalSize.Width <= targetSize.Width && originalSize.Height <= targetSize.Height)
        {
            return originalSize;
        }

        float scaleX = targetSize.Width / originalSize.Width;
        float scaleY = targetSize.Height / originalSize.Height;
        float scale = Math.Min(scaleX, scaleY);

        return new SizeF(originalSize.Width * scale, originalSize.Height * scale);
    }
}

