/**
 * Image Optimization Pipeline for Quote2Contract
 * Handles image compression, format conversion, and responsive image generation
 */

import sharp from 'sharp';

export interface ImageOptimizationOptions {
  quality?: number;
  width?: number;
  height?: number;
  format?: 'jpeg' | 'png' | 'webp' | 'avif';
  fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
}

export interface OptimizedImage {
  buffer: Buffer;
  format: string;
  width: number;
  height: number;
  size: number;
}

/**
 * Optimize a single image
 */
export async function optimizeImage(
  inputBuffer: Buffer,
  options: ImageOptimizationOptions = {}
): Promise<OptimizedImage> {
  const {
    quality = 80,
    width,
    height,
    format = 'webp',
    fit = 'cover',
  } = options;

  let pipeline = sharp(inputBuffer);

  // Resize if dimensions provided
  if (width || height) {
    pipeline = pipeline.resize(width, height, { fit });
  }

  // Convert to specified format with quality settings
  switch (format) {
    case 'jpeg':
      pipeline = pipeline.jpeg({ quality, mozjpeg: true });
      break;
    case 'png':
      pipeline = pipeline.png({ quality, compressionLevel: 9 });
      break;
    case 'webp':
      pipeline = pipeline.webp({ quality, effort: 6 });
      break;
    case 'avif':
      pipeline = pipeline.avif({ quality, effort: 6 });
      break;
  }

  const outputBuffer = await pipeline.toBuffer();
  const metadata = await sharp(outputBuffer).metadata();

  return {
    buffer: outputBuffer,
    format: metadata.format || format,
    width: metadata.width || 0,
    height: metadata.height || 0,
    size: outputBuffer.length,
  };
}

/**
 * Generate responsive image variants (srcset)
 */
export async function generateResponsiveImages(
  inputBuffer: Buffer,
  widths: number[] = [320, 640, 768, 1024, 1280, 1920]
): Promise<Map<number, OptimizedImage>> {
  const images = new Map<number, OptimizedImage>();

  for (const width of widths) {
    try {
      const optimized = await optimizeImage(inputBuffer, {
        width,
        format: 'webp',
        quality: 80,
      });
      images.set(width, optimized);
    } catch (error) {
      console.error(`Failed to generate ${width}px variant:`, error);
    }
  }

  return images;
}

/**
 * Convert image to multiple formats (WebP, AVIF fallback)
 */
export async function convertToModernFormats(
  inputBuffer: Buffer,
  width?: number
): Promise<{ webp: OptimizedImage; avif?: OptimizedImage; fallback: OptimizedImage }> {
  const [webp, avif, fallback] = await Promise.all([
    optimizeImage(inputBuffer, { width, format: 'webp', quality: 85 }),
    optimizeImage(inputBuffer, { width, format: 'avif', quality: 80 }).catch(() => null),
    optimizeImage(inputBuffer, { width, format: 'jpeg', quality: 80 }),
  ]);

  return {
    webp,
    avif: avif || undefined,
    fallback,
  };
}

/**
 * Get image metadata
 */
export async function getImageMetadata(inputBuffer: Buffer) {
  const metadata = await sharp(inputBuffer).metadata();
  
  return {
    width: metadata.width,
    height: metadata.height,
    format: metadata.format,
    space: metadata.space,
    channels: metadata.channels,
    depth: metadata.depth,
    density: metadata.density,
    hasAlpha: metadata.hasAlpha,
    orientation: metadata.orientation,
    size: inputBuffer.length,
  };
}

/**
 * Create thumbnail
 */
export async function createThumbnail(
  inputBuffer: Buffer,
  size: number = 200
): Promise<OptimizedImage> {
  return optimizeImage(inputBuffer, {
    width: size,
    height: size,
    format: 'webp',
    quality: 75,
    fit: 'cover',
  });
}

/**
 * Compress image for web
 */
export async function compressForWeb(
  inputBuffer: Buffer,
  maxWidth: number = 1920,
  maxHeight: number = 1080
): Promise<OptimizedImage> {
  const metadata = await sharp(inputBuffer).metadata();
  
  let width = metadata.width;
  let height = metadata.height;
  
  // Calculate resize dimensions while maintaining aspect ratio
  if (width && height) {
    if (width > maxWidth || height > maxHeight) {
      const ratio = Math.min(maxWidth / width, maxHeight / height);
      width = Math.floor(width * ratio);
      height = Math.floor(height * ratio);
    }
  }
  
  return optimizeImage(inputBuffer, {
    width,
    height,
    format: 'webp',
    quality: 85,
  });
}

/**
 * Batch process images
 */
export async function batchOptimizeImages(
  images: Array<{ buffer: Buffer; name: string }>,
  options: ImageOptimizationOptions = {}
): Promise<Map<string, OptimizedImage>> {
  const results = new Map<string, OptimizedImage>();

  await Promise.all(
    images.map(async ({ buffer, name }) => {
      try {
        const optimized = await optimizeImage(buffer, options);
        results.set(name, optimized);
      } catch (error) {
        console.error(`Failed to optimize ${name}:`, error);
      }
    })
  );

  return results;
}

/**
 * Calculate compression ratio
 */
export function calculateCompressionRatio(originalSize: number, compressedSize: number): number {
  return Math.round(((originalSize - compressedSize) / originalSize) * 100);
}

/**
 * Format file size for display
 */
export function formatFileSize(bytes: number): string {
  if (bytes === 0) return '0 Bytes';

  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));

  return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
}
