/**
 * Image Optimization Middleware
 * High-performance image serving with streaming and caching
 */
const path = require("path");
const fs = require("fs");
const fsPromises = require("fs").promises;
const logger = require("../config/logger");

// Cache for image metadata (not content)
const metadataCache = new Map();
const METADATA_CACHE_TTL = 600000; // 10 minutes
const METADATA_CACHE_MAX = 1000;

// Image mime types
const MIME_TYPES = {
  ".jpg": "image/jpeg",
  ".jpeg": "image/jpeg",
  ".png": "image/png",
  ".gif": "image/gif",
  ".webp": "image/webp",
  ".svg": "image/svg+xml",
  ".ico": "image/x-icon",
  ".avif": "image/avif",
};

/**
 * Get or cache image metadata
 */
async function getImageMetadata(filePath) {
  const cached = metadataCache.get(filePath);
  if (cached && Date.now() - cached.timestamp < METADATA_CACHE_TTL) {
    return cached.data;
  }

  try {
    const stats = await fsPromises.stat(filePath);
    const metadata = {
      exists: true,
      size: stats.size,
      mtime: stats.mtime.getTime(),
      etag: `"${stats.size}-${stats.mtime.getTime()}"`,
      lastModified: stats.mtime.toUTCString(),
    };

    // LRU eviction
    if (metadataCache.size >= METADATA_CACHE_MAX) {
      const firstKey = metadataCache.keys().next().value;
      metadataCache.delete(firstKey);
    }

    metadataCache.set(filePath, { data: metadata, timestamp: Date.now() });
    return metadata;
  } catch {
    const notFound = { exists: false };
    metadataCache.set(filePath, { data: notFound, timestamp: Date.now() });
    return notFound;
  }
}

/**
 * Serve optimized images with streaming and aggressive caching
 */
const imageOptimization = (uploadsDir) => {
  return async (req, res, next) => {
    // Only handle image requests
    const ext = path.extname(req.path).toLowerCase();
    if (!MIME_TYPES[ext]) {
      return next();
    }

    const imagePath = path.join(uploadsDir, req.path.replace("/uploads/", ""));

    // Get cached metadata
    const metadata = await getImageMetadata(imagePath);
    if (!metadata.exists) {
      return next();
    }

    try {
      // Check if client has cached version (304 Not Modified)
      const ifNoneMatch = req.get("if-none-match");
      const ifModifiedSince = req.get("if-modified-since");

      if (
        ifNoneMatch === metadata.etag ||
        ifModifiedSince === metadata.lastModified
      ) {
        return res.status(304).end();
      }

      // Set aggressive caching headers
      res.set({
        "Content-Type": MIME_TYPES[ext],
        "Content-Length": metadata.size,
        "Cache-Control": "public, max-age=31536000, immutable", // 1 year
        ETag: metadata.etag,
        "Last-Modified": metadata.lastModified,
        Vary: "Accept-Encoding",
        "X-Content-Type-Options": "nosniff",
      });

      // Use streaming for efficient memory usage
      const readStream = fs.createReadStream(imagePath, {
        highWaterMark: 64 * 1024, // 64KB chunks
      });

      readStream.on("error", (error) => {
        logger.error("Image stream error:", {
          path: imagePath,
          error: error.message,
        });
        if (!res.headersSent) {
          res.status(500).end();
        }
      });

      readStream.pipe(res);
    } catch (error) {
      logger.error("Image serve error:", {
        path: imagePath,
        error: error.message,
      });
      next();
    }
  };
};

module.exports = { imageOptimization };
