// filmstrip.js — server-side filmstrip generation worker
//
// Downloads the proxy from S3, uses FFmpeg to extract FRAME_COUNT evenly-spaced
// JPEG frames, encodes them as base64, packs into a JSON array, and uploads to
// S3 at filmstrips/<assetId>.json. The API returns a signed URL for this file
// and the frontend fetches + displays it — no browser seek loop needed.

import { join } from 'path';
import { tmpdir } from 'os';
import { mkdir, readdir, readFile, writeFile, rm } from 'fs/promises';
import { query } from '../db/client.js';
import { downloadFromS3, uploadToS3 } from '../s3/client.js';
import { runFFmpeg, getMediaDuration } from '../ffmpeg/executor.js';

const S3_BUCKET  = process.env.S3_BUCKET  || 'wild-dragon';
const FRAME_COUNT = 28;
const FRAME_W     = 160;
const FRAME_H     = 90;

export const filmstripWorker = async (job) => {
  const { assetId, proxyKey } = job.data;

  const tmpDir  = join(tmpdir(), `filmstrip-${job.id}`);
  const srcPath = join(tmpDir, 'proxy.mp4');

  try {
    await mkdir(tmpDir, { recursive: true });

    // 1. Download proxy from S3
    await job.updateProgress(5);
    console.log(`[filmstrip] Downloading ${proxyKey} for asset ${assetId}`);
    await downloadFromS3(S3_BUCKET, proxyKey, srcPath);

    // 2. Get duration so we can spread frames evenly
    await job.updateProgress(15);
    const durationSec = await getMediaDuration(srcPath);
    if (!durationSec || durationSec <= 0) throw new Error('Could not determine video duration');

    // 3. Extract FRAME_COUNT frames evenly spaced across the clip using FFmpeg
    // fps filter: select one frame every (duration / frameCount) seconds.
    // select=not(mod(n\,step)) is less reliable than fps for variable-frame content.
    const interval   = durationSec / FRAME_COUNT;
    const outputGlob = join(tmpDir, 'frame-%03d.jpg');

    await job.updateProgress(20);
    console.log(`[filmstrip] Extracting ${FRAME_COUNT} frames from ${durationSec.toFixed(1)}s clip`);

    await runFFmpeg([
      '-i', srcPath,
      '-vf', `fps=1/${interval.toFixed(4)},scale=${FRAME_W}:${FRAME_H}:force_original_aspect_ratio=decrease,pad=${FRAME_W}:${FRAME_H}:(ow-iw)/2:(oh-ih)/2`,
      '-frames:v', String(FRAME_COUNT),
      '-q:v', '5',     // JPEG quality 1-31, lower = better; 5 ≈ ~85% quality
      '-y',
      outputGlob,
    ]);

    await job.updateProgress(70);

    // 4. Read extracted frames, encode as base64
    const entries = (await readdir(tmpDir))
      .filter(f => f.startsWith('frame-') && f.endsWith('.jpg'))
      .sort();

    if (entries.length === 0) throw new Error('FFmpeg produced no frame files');

    const frames = await Promise.all(
      entries.map(async (f) => {
        const buf = await readFile(join(tmpDir, f));
        return 'data:image/jpeg;base64,' + buf.toString('base64');
      })
    );

    await job.updateProgress(85);

    // 5. Upload JSON array to S3
    const s3Key = `filmstrips/${assetId}.json`;
    const json  = JSON.stringify(frames);
    const jsonPath = join(tmpDir, 'filmstrip.json');
    await writeFile(jsonPath, json);
    await uploadToS3(S3_BUCKET, s3Key, jsonPath);

    await job.updateProgress(95);

    // 6. Store s3Key in assets table
    await query(
      `UPDATE assets SET filmstrip_s3_key = $1, updated_at = NOW() WHERE id = $2`,
      [s3Key, assetId]
    );

    await job.updateProgress(100);
    console.log(`[filmstrip] Asset ${assetId} filmstrip complete (${frames.length} frames) → ${s3Key}`);
    return { assetId, s3Key, frameCount: frames.length };

  } catch (error) {
    console.error(`[filmstrip] Error for asset ${assetId}:`, error.message);
    throw error;
  } finally {
    await rm(tmpDir, { recursive: true, force: true }).catch(() => {});
  }
};
