import { exec } from 'child_process';
import { promisify } from 'util';
import path from 'path';
import fs from 'fs';

const execAsync = promisify(exec);

export interface GifOptions {
  fps?: number;        // Frames per second (default: 10)
  width?: number;      // Width in pixels (default: 300)
  duration?: number;   // Duration in seconds to capture (default: 3)
  startTime?: number;  // Start time in seconds (default: 0)
}

/**
 * Generate a GIF from a video file using ffmpeg
 * @param videoPath - Absolute path to the video file
 * @param outputPath - Absolute path where GIF should be saved
 * @param options - GIF generation options
 * @returns Promise<string> - Path to generated GIF
 */
export async function generateGifFromVideo(
  videoPath: string,
  outputPath: string,
  options: GifOptions = {}
): Promise<string> {
  const {
    fps = 10,
    width = 300,
    duration = 3,
    startTime = 0,
  } = options;

  // Ensure output directory exists
  const outputDir = path.dirname(outputPath);
  if (!fs.existsSync(outputDir)) {
    fs.mkdirSync(outputDir, { recursive: true });
  }

  // Build ffmpeg command
  // -ss: start time
  // -t: duration
  // -vf: video filters (fps, scale, palettegen/paletteuse for better quality)
  const paletteFile = path.join(outputDir, `palette-${Date.now()}.png`);
  
  try {
    // Step 1: Generate color palette for better GIF quality
    const paletteCmd = `ffmpeg -ss ${startTime} -t ${duration} -i "${videoPath}" -vf "fps=${fps},scale=${width}:-1:flags=lanczos,palettegen" -y "${paletteFile}"`;
    await execAsync(paletteCmd);

    // Step 2: Generate GIF using the palette
    const gifCmd = `ffmpeg -ss ${startTime} -t ${duration} -i "${videoPath}" -i "${paletteFile}" -lavfi "fps=${fps},scale=${width}:-1:flags=lanczos[x];[x][1:v]paletteuse" -y "${outputPath}"`;
    await execAsync(gifCmd);

    // Clean up palette file
    if (fs.existsSync(paletteFile)) {
      fs.unlinkSync(paletteFile);
    }

    return outputPath;
  } catch (error: any) {
    // Clean up on error
    if (fs.existsSync(paletteFile)) {
      fs.unlinkSync(paletteFile);
    }
    if (fs.existsSync(outputPath)) {
      fs.unlinkSync(outputPath);
    }
    throw new Error(`Failed to generate GIF: ${error.message}`);
  }
}

/**
 * Get video duration in seconds using ffprobe
 * @param videoPath - Absolute path to the video file
 * @returns Promise<number> - Duration in seconds
 */
export async function getVideoDuration(videoPath: string): Promise<number> {
  try {
    const cmd = `ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${videoPath}"`;
    const { stdout } = await execAsync(cmd);
    return parseFloat(stdout.trim());
  } catch (error: any) {
    throw new Error(`Failed to get video duration: ${error.message}`);
  }
}

