#!/usr/bin/env node
/**
 * Script to preprocess image directories and generate thumbnail data URIs
 * to be stored in files.lst files.
 *
 * Usage:
 *   node generate-blurhashes.js <directory>
 *
 * Example:
 *   node generate-blurhashes.js ../content/motion_source/monstera1
 */

const fs = require("fs");
const path = require("path");
const { createCanvas, loadImage } = require("canvas");

// Configuration
const MAX_THUMBNAIL_SIZE = 32;

/**
 * Create a thumbnail data URI for an image
 * @param {string} imagePath - Path to the image
 * @returns {Promise<string>} The data URI
 */
async function createThumbnailDataURI(imagePath) {
  try {
    const image = await loadImage(imagePath);

    // Create a small canvas for thumbnail
    const aspectRatio = image.width / image.height;
    let thumbnailWidth = MAX_THUMBNAIL_SIZE;
    let thumbnailHeight = MAX_THUMBNAIL_SIZE;
    if (aspectRatio > 1) {
      thumbnailHeight = Math.round(thumbnailWidth / aspectRatio);
    } else {
      thumbnailWidth = Math.round(thumbnailHeight * aspectRatio);
    }

    const canvas = createCanvas(thumbnailWidth, thumbnailHeight);
    const ctx = canvas.getContext("2d");

    // Draw image to thumbnail size
    ctx.drawImage(image, 0, 0, thumbnailWidth, thumbnailHeight);

    // Convert to data URI
    const dataURI = canvas.toDataURL("image/png");
    return dataURI;
  } catch (err) {
    console.error(`Error processing ${imagePath}:`, err);
    return null;
  }
}

/**
 * Process a directory and update its files.lst with thumbnail data URIs
 * @param {string} dirPath - Path to the directory containing images
 */
async function processDirectory(dirPath) {
  console.log(`Processing directory: ${dirPath}`);

  // Read directory for image files
  const files = fs
    .readdirSync(dirPath)
    .filter((file) =>
      [".jpg", ".jpeg", ".png", ".webp", ".gif"].includes(
        path.extname(file).toLowerCase()
      )
    )
    .sort((a, b) => {
      // Natural sort for numbered files (e.g., img001.jpg, img002.jpg)
      const numA = parseInt(a.match(/\d+/) || "0");
      const numB = parseInt(b.match(/\d+/) || "0");
      return numA - numB;
    });

  if (files.length === 0) {
    console.warn(`No image files found in ${dirPath}`);
    return;
  }

  // Process each file and collect blurhashes
  const fileData = [];
  let count = 0;
  const total = files.length;

  for (const file of files) {
    count++;
    const filePath = path.join(dirPath, file);
    process.stdout.write(`\rProcessing image ${count}/${total}: ${file}`);

    const dataURI = await createThumbnailDataURI(filePath);
    if (dataURI) {
      fileData.push({ file, dataURI });
    } else {
      // Include file without data URI if creation fails
      fileData.push({ file, dataURI: null });
    }
  }

  console.log("\nWriting files.lst...");

  // Write to files.lst
  const outputPath = path.join(dirPath, "files.lst");
  const fileLines = fileData.map((entry) => {
    if (entry.dataURI) {
      return `${entry.file}\t${entry.dataURI}`;
    }
    return entry.file;
  });

  fs.writeFileSync(outputPath, fileLines.join("\n"));
  console.log(
    `Created files.lst with ${fileData.length} entries (${
      fileData.filter((e) => e.dataURI).length
    } with thumbnail data URIs)`
  );
}

// Main execution
async function main() {
  const args = process.argv.slice(2);

  if (args.length === 0) {
    console.error("Please provide a directory path");
    process.exit(1);
  }

  const dirPath = args[0];

  if (!fs.existsSync(dirPath)) {
    console.error(`Directory does not exist: ${dirPath}`);
    process.exit(1);
  }

  if (!fs.statSync(dirPath).isDirectory()) {
    console.error(`Not a directory: ${dirPath}`);
    process.exit(1);
  }

  await processDirectory(dirPath);
}

main().catch((err) => {
  console.error("Error:", err);
  process.exit(1);
});
