using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Formats.Jpeg;

namespace SIGCM.Infrastructure.Services;

public class ImageOptimizationService
{
    // Configuración de tamaños
    private const int MAX_WIDTH = 1920;
    private const int MAX_HEIGHT = 1080;
    private const int THUMBNAIL_WIDTH = 400;
    private const int THUMBNAIL_HEIGHT = 300;
    
    // Configuración de calidad
    private const int WEBP_QUALITY = 85;
    private const int JPEG_QUALITY = 90;

    /// <summary>
    /// Optimiza una imagen: resize, compresión y conversión a WebP
    /// </summary>
    public async Task<ImageOptimizationResult> OptimizeImageAsync(Stream inputStream, string originalFileName)
    {
        var result = new ImageOptimizationResult
        {
            OriginalFileName = originalFileName,
            ProcessedAt = DateTime.UtcNow
        };

        try
        {
            using var image = await Image.LoadAsync(inputStream);
            
            result.OriginalWidth = image.Width;
            result.OriginalHeight = image.Height;
            result.OriginalSize = inputStream.Length;

            // 1. RESIZE si es necesario
            if (image.Width > MAX_WIDTH || image.Height > MAX_HEIGHT)
            {
                image.Mutate(x => x.Resize(new ResizeOptions
                {
                    Size = new Size(MAX_WIDTH, MAX_HEIGHT),
                    Mode = ResizeMode.Max, // Mantiene aspect ratio
                    Sampler = KnownResamplers.Lanczos3 // Alta calidad
                }));
            }

            result.OptimizedWidth = image.Width;
            result.OptimizedHeight = image.Height;

            // 2. CONVERSIÓN A WEBP (imagen principal)
            var webpStream = new MemoryStream();
            var webpEncoder = new WebpEncoder
            {
                Quality = WEBP_QUALITY,
                Method = WebpEncodingMethod.BestQuality
            };
            
            await image.SaveAsync(webpStream, webpEncoder);
            webpStream.Position = 0;
            result.WebpData = webpStream.ToArray();
            result.WebpSize = result.WebpData.Length;

            // 3. THUMBNAIL (miniatura para listados)
            var thumbnail = image.Clone(x => x.Resize(new ResizeOptions
            {
                Size = new Size(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT),
                Mode = ResizeMode.Max,
                Sampler = KnownResamplers.Lanczos3
            }));

            var thumbStream = new MemoryStream();
            await thumbnail.SaveAsync(thumbStream, webpEncoder);
            thumbStream.Position = 0;
            result.ThumbnailData = thumbStream.ToArray();
            result.ThumbnailSize = result.ThumbnailData.Length;

            // 4. FALLBACK JPEG (para navegadores antiguos)
            var jpegStream = new MemoryStream();
            var jpegEncoder = new JpegEncoder { Quality = JPEG_QUALITY };
            await image.SaveAsync(jpegStream, jpegEncoder);
            jpegStream.Position = 0;
            result.JpegData = jpegStream.ToArray();
            result.JpegSize = result.JpegData.Length;

            // Calcular reducción de tamaño
            result.CompressionRatio = (1 - (double)result.WebpSize / result.OriginalSize) * 100;

            thumbnail.Dispose();
        }
        catch (Exception ex)
        {
            result.Error = ex.Message;
        }

        return result;
    }

    /// <summary>
    /// Genera solo un thumbnail rápido
    /// </summary>
    public async Task<byte[]> GenerateThumbnailAsync(Stream inputStream, int width = 200, int height = 150)
    {
        using var image = await Image.LoadAsync(inputStream);
        
        image.Mutate(x => x.Resize(new ResizeOptions
        {
            Size = new Size(width, height),
            Mode = ResizeMode.Crop, // Recorta para mantener dimensiones exactas
            Sampler = KnownResamplers.Lanczos3
        }));

        var stream = new MemoryStream();
        var encoder = new WebpEncoder { Quality = 80 };
        await image.SaveAsync(stream, encoder);
        
        return stream.ToArray();
    }

    /// <summary>
    /// Valida que el archivo sea realmente una imagen
    /// </summary>
    public async Task<bool> IsValidImageAsync(Stream stream)
    {
        try
        {
            var imageInfo = await Image.IdentifyAsync(stream);
            stream.Position = 0; // Reset para uso posterior
            return imageInfo != null;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Obtiene información básica de la imagen sin cargarla completamente
    /// </summary>
    public async Task<(int Width, int Height, string Format)> GetImageInfoAsync(Stream stream)
    {
        var imageInfo = await Image.IdentifyAsync(stream);
        stream.Position = 0;
        
        return (imageInfo.Width, imageInfo.Height, imageInfo.Metadata.DecodedImageFormat?.Name ?? "Unknown");
    }
}

// Resultado de la optimización
public class ImageOptimizationResult
{
    public string OriginalFileName { get; set; } = string.Empty;
    public DateTime ProcessedAt { get; set; }
    
    // Dimensiones originales
    public int OriginalWidth { get; set; }
    public int OriginalHeight { get; set; }
    public long OriginalSize { get; set; }
    
    // Dimensiones optimizadas
    public int OptimizedWidth { get; set; }
    public int OptimizedHeight { get; set; }
    
    // Archivos generados
    public byte[]? WebpData { get; set; }
    public long WebpSize { get; set; }
    
    public byte[]? ThumbnailData { get; set; }
    public long ThumbnailSize { get; set; }
    
    public byte[]? JpegData { get; set; }
    public long JpegSize { get; set; }
    
    // Métricas
    public double CompressionRatio { get; set; }
    
    // Error (si hubo)
    public string? Error { get; set; }
    
    public bool Success => string.IsNullOrEmpty(Error);
}
