import path from 'path';
import fs from 'fs/promises';
import sharp from 'sharp';
import { ProcessingJob } from '../models/ProcessingJob.js';

export class ImageProcessor {
  constructor() {
    this.supportedFormats = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'webp', 'avif', 'heic'];
    this.outputFormats = ['webp', 'avif', 'jpeg', 'png'];
  }

  async processImage(jobId, inputPath, outputPath, options) {
    try {
      await ProcessingJob.updateStatus(jobId, 'processing', 0);

      // Read the image with Sharp
      let image = sharp(inputPath);
      
      // Get image metadata
      const metadata = await image.metadata();
      await ProcessingJob.updateStatus(jobId, 'processing', 25);

      // Get original file stats
      const originalStats = await fs.stat(inputPath);
      const originalSize = originalStats.size;

      // Apply format conversion and quality settings
      switch (options.format) {
        case 'webp':
          image = image.webp({ 
            quality: options.quality,
            effort: 6, // Higher effort for better compression
            lossless: false
          });
          break;
        case 'avif':
          image = image.avif({ 
            quality: options.quality,
            effort: 6,
            lossless: false
          });
          break;
        case 'jpeg':
          image = image.jpeg({ 
            quality: options.quality,
            progressive: true,
            mozjpeg: true,
            optimiseScans: true
          });
          break;
        case 'png':
          // For PNG, we use compression level instead of quality
          const compressionLevel = Math.round((100 - options.quality) / 10);
          image = image.png({ 
            compressionLevel: 9,
            progressive: true,
            palette: options.quality < 90 // Use palette for lower quality
          });
          break;
        default:
          image = image.webp({ 
            quality: options.quality,
            effort: 6,
            lossless: false
          });
      }

      await ProcessingJob.updateStatus(jobId, 'processing', 50);

      // Apply additional compression for larger files
      if (originalSize > 1024 * 1024) { // Files larger than 1MB
        // Resize if image is very large to help with compression
        if (metadata.width > 2048 || metadata.height > 2048) {
          image = image.resize(2048, 2048, {
            fit: 'inside',
            withoutEnlargement: true
          });
        }
      }

      // Handle metadata preservation
      if (!options.preserveMetadata) {
        image = image.withMetadata({
          exif: {},
          icc: metadata.icc, // Keep color profile for quality
        });
      }

      await ProcessingJob.updateStatus(jobId, 'processing', 75);

      // Write the processed image
      await image.toFile(outputPath);
      await ProcessingJob.updateStatus(jobId, 'processing', 90);

      // Get optimized file size
      const optimizedStats = await fs.stat(outputPath);
      const optimizedSize = optimizedStats.size;

      // Update job with final results
      await ProcessingJob.updateOptimizedSize(jobId, optimizedSize);
      await ProcessingJob.updateStatus(jobId, 'completed', 100);

      return {
        success: true,
        originalSize,
        optimizedSize,
        compressionRatio: ((originalSize - optimizedSize) / originalSize * 100).toFixed(2)
      };

    } catch (error) {
      console.error(`Image processing error for job ${jobId}:`, error);
      await ProcessingJob.updateStatus(jobId, 'failed', 0, error.message);
      throw error;
    }
  }

  async processImageBuffer(buffer, options) {
    try {
      // Read image from buffer with Sharp
      let image = sharp(buffer);
      
      // Get metadata
      const metadata = await image.metadata();

      // Apply format conversion and quality settings
      switch (options.format) {
        case 'webp':
          image = image.webp({ 
            quality: options.quality,
            effort: 6,
            lossless: false
          });
          break;
        case 'avif':
          image = image.avif({ 
            quality: options.quality,
            effort: 6,
            lossless: false
          });
          break;
        case 'jpeg':
          image = image.jpeg({ 
            quality: options.quality,
            progressive: true,
            mozjpeg: true,
            optimiseScans: true
          });
          break;
        case 'png':
          const compressionLevel = Math.round((100 - options.quality) / 10);
          image = image.png({ 
            compressionLevel: 9,
            progressive: true,
            palette: options.quality < 90
          });
          break;
        default:
          image = image.webp({ 
            quality: options.quality,
            effort: 6,
            lossless: false
          });
      }

      // Handle metadata preservation
      if (!options.preserveMetadata) {
        image = image.withMetadata({
          exif: {},
          icc: metadata.icc, // Keep color profile for quality
        });
      }

      // Get processed buffer
      const processedBuffer = await image.toBuffer();

      return {
        buffer: processedBuffer,
        originalSize: buffer.length,
        optimizedSize: processedBuffer.length,
        compressionRatio: ((buffer.length - processedBuffer.length) / buffer.length * 100).toFixed(2)
      };

    } catch (error) {
      throw new Error(`Image processing failed: ${error.message}`);
    }
  }

  generateSeoFilename(originalName, template, keywords = '') {
    const nameWithoutExt = path.parse(originalName).name;
    const keywordArray = keywords.split(',').map(k => k.trim()).filter(k => k);
    
    let filename = template
      .replace(/{name}/g, nameWithoutExt)
      .replace(/{keyword}/g, keywordArray[0] || '')
      .replace(/{keywords}/g, keywordArray.join('-'))
      .replace(/{timestamp}/g, Date.now())
      .replace(/{date}/g, new Date().toISOString().split('T')[0]);

    // Clean up filename
    filename = filename
      .toLowerCase()
      .replace(/[^a-z0-9-]/g, '-')
      .replace(/-+/g, '-')
      .replace(/^-|-$/g, '');

    return filename;
  }

  getOutputExtension(format) {
    switch (format) {
      case 'webp':
        return 'webp';
      case 'avif':
        return 'avif';
      case 'jpeg':
        return 'jpg';
      case 'png':
        return 'png';
      default:
        return 'webp';
    }
  }

  isValidImageFormat(filename) {
    const ext = path.extname(filename).toLowerCase().substring(1);
    return this.supportedFormats.includes(ext);
  }

  async getImageInfo(inputPath) {
    try {
      const image = sharp(inputPath);
      const metadata = await image.metadata();
      const stats = await fs.stat(inputPath);
      
      return {
        width: metadata.width,
        height: metadata.height,
        format: metadata.format,
        size: stats.size,
        hasAlpha: metadata.hasAlpha,
        colorSpace: metadata.space
      };
    } catch (error) {
      throw new Error(`Failed to get image info: ${error.message}`);
    }
  }
}

export const imageProcessor = new ImageProcessor();