namespace Sonex.Services.ImageSync;

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.Versioning;

internal static class ImageResizer
{
    public static ResizeResult ProcessFile(
        string sourcePath,
        string destinationRoot,
        string targetRelativePath,
        DateTime sourceLastWriteUtc,
        IReadOnlyList<ImageSize> sizes)
    {
        using var sourceStream = new FileStream(
            sourcePath,
            FileMode.Open,
            FileAccess.Read,
            FileShare.ReadWrite | FileShare.Delete);

        using var sourceImage = Image.FromStream(sourceStream, useEmbeddedColorManagement: false, validateImageData: true);

        foreach (ImageSize size in sizes)
        {
            string destinationPath = BuildDestinationPath(destinationRoot, size, targetRelativePath);
            string? destinationDirectory = Path.GetDirectoryName(destinationPath);

            if (!string.IsNullOrWhiteSpace(destinationDirectory))
                Directory.CreateDirectory(destinationDirectory);

            SaveResizedImage(sourceImage, destinationPath, size);
            File.SetLastWriteTimeUtc(destinationPath, sourceLastWriteUtc);
        }

        return new ResizeResult(sourceImage.Width, sourceImage.Height);
    }

    private static string BuildDestinationPath(string destinationRoot, ImageSize size, string targetRelativePath)
    {
        string safeRelativePath = targetRelativePath.Replace('/', Path.DirectorySeparatorChar);
        return Path.Combine(destinationRoot, size.FolderName, safeRelativePath);
    }

    [SupportedOSPlatform("windows")]
    private static void SaveResizedImage(
        Image sourceImage,
        string destinationPath,
        ImageSize size)
    {
        float horizontalResolution = sourceImage.HorizontalResolution > 0 ? sourceImage.HorizontalResolution : 96f;
        float verticalResolution = sourceImage.VerticalResolution > 0 ? sourceImage.VerticalResolution : 96f;

        using var canvas = new Bitmap(size.Width, size.Height, PixelFormat.Format24bppRgb);

        canvas.SetResolution(horizontalResolution, verticalResolution);

        using var graphics = Graphics.FromImage(canvas);
        graphics.CompositingMode = CompositingMode.SourceOver;
        graphics.CompositingQuality = CompositingQuality.HighQuality;
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
        graphics.SmoothingMode = SmoothingMode.HighQuality;
        graphics.Clear(Color.White);

        Rectangle targetRectangle = CalculateTargetRectangle(sourceImage.Width, sourceImage.Height, size.Width, size.Height);
        graphics.DrawImage(
            sourceImage,
            targetRectangle,
            0,
            0,
            sourceImage.Width,
            sourceImage.Height,
            GraphicsUnit.Pixel);

        SaveBitmap(canvas, destinationPath);
    }

    private static Rectangle CalculateTargetRectangle(int sourceWidth, int sourceHeight, int targetWidth, int targetHeight)
    {
        double scale = Math.Min((double)targetWidth / sourceWidth, (double)targetHeight / sourceHeight);

        int resizedWidth = Math.Max(1, (int)Math.Round(sourceWidth * scale));
        int resizedHeight = Math.Max(1, (int)Math.Round(sourceHeight * scale));
        int offsetX = (targetWidth - resizedWidth) / 2;
        int offsetY = (targetHeight - resizedHeight) / 2;

        return new Rectangle(offsetX, offsetY, resizedWidth, resizedHeight);
    }

    private static void SaveBitmap(Bitmap bitmap, string destinationPath)
    {
        ImageCodecInfo? jpegEncoder = ImageCodecInfo.GetImageEncoders()
            .FirstOrDefault(x => x.FormatID == ImageFormat.Jpeg.Guid);

        if (jpegEncoder is not null)
        {
            using var encoderParameters = new EncoderParameters(1);
            encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 92L);
            bitmap.Save(destinationPath, jpegEncoder, encoderParameters);
            return;
        }

        bitmap.Save(destinationPath, ImageFormat.Jpeg);
    }
}

internal readonly record struct ResizeResult(int Width, int Height);
