// Engagement Heatmap (V22.5)
//
// Reuses the AI Editor pipeline (`score-segments.ts`) to compute a per-
// timestamp "engagement score" combining:
//   - Scene change density
//   - Audio loudness peaks
//
// We downsample into N "buckets" across the timeline and return each
// bucket's normalised score 0..1. The Timeline component renders this as
// a coloured heatmap strip.

export interface HeatmapBucket {
  /** Bucket start (seconds). */
  start: number;
  /** Bucket end (seconds). */
  end: number;
  /** Normalised score 0..1 (0 = dead, 1 = peak). */
  score: number;
  /** Optional category label. */
  category?: 'quiet' | 'normal' | 'busy' | 'peak';
}

export interface EngagementInputs {
  /** Source duration (seconds). */
  duration: number;
  /** Scene-change timestamps in seconds. */
  sceneChanges: number[];
  /** Per-window loudness dB (-60..0). */
  loudnessDb: number[];
  /** Start time of window i in loudnessDb. */
  rmsWindowsStart: number[];
  /** Total number of buckets to produce (default 80). */
  bucketCount?: number;
}

/**
 * Combine scene-change density + loudness into a normalised score.
 * Output buckets are uniformly distributed across [0, duration].
 */
export function computeHeatmap(inputs: EngagementInputs): HeatmapBucket[] {
  const bucketCount = inputs.bucketCount ?? 80;
  const dur = inputs.duration;
  if (dur <= 0) return [];

  const bucketSec = dur / bucketCount;
  const buckets: HeatmapBucket[] = [];
  for (let i = 0; i < bucketCount; i++) {
    const start = i * bucketSec;
    const end = (i + 1) * bucketSec;
    // Scene density: how many scene changes fall in this bucket?
    const sceneCount = inputs.sceneChanges.filter(
      (t) => t >= start && t < end,
    ).length;
    // Loudness: average dB in this bucket
    let loudSum = 0;
    let loudN = 0;
    for (let j = 0; j < inputs.loudnessDb.length; j++) {
      const t = inputs.rmsWindowsStart[j] ?? 0;
      if (t >= start && t < end) {
        loudSum += inputs.loudnessDb[j];
        loudN++;
      }
    }
    const loudDb = loudN > 0 ? loudSum / loudN : -60;
    // Normalise loudness -60..0 → 0..1
    const loudNorm = Math.max(0, Math.min(1, (loudDb + 60) / 60));
    // Normalise scene count (0..maxScenesPerBucket) → 0..1
    const sceneNorm = Math.min(1, sceneCount / 3);
    // Combined: 60% loudness + 40% scene activity
    const score = loudNorm * 0.6 + sceneNorm * 0.4;

    let category: HeatmapBucket['category'];
    if (score < 0.15) category = 'quiet';
    else if (score < 0.45) category = 'normal';
    else if (score < 0.75) category = 'busy';
    else category = 'peak';

    buckets.push({ start, end, score, category });
  }
  return buckets;
}

/** Get color for a bucket (HSL interpolation: cool blue → warm red). */
export function bucketColor(bucket: HeatmapBucket): string {
  const t = bucket.score;
  // blue (220°) → green (140°) → yellow (60°) → red (0°)
  const hue = 220 - t * 220;
  const sat = 70;
  const light = 35 + t * 20;
  return `hsl(${hue.toFixed(0)}, ${sat}%, ${light}%)`;
}

/** Aggregate summary for the AI panel header. */
export interface EngagementSummary {
  duration: number;
  peakSeconds: number;
  quietSeconds: number;
  sceneChanges: number;
  averageScore: number;
}

export function summariseHeatmap(
  buckets: HeatmapBucket[],
  sceneChangeCount: number,
): EngagementSummary {
  if (buckets.length === 0) {
    return { duration: 0, peakSeconds: 0, quietSeconds: 0, sceneChanges: 0, averageScore: 0 };
  }
  const dur = buckets[buckets.length - 1].end - buckets[0].start;
  let peak = 0;
  let quiet = 0;
  let sum = 0;
  for (const b of buckets) {
    const len = b.end - b.start;
    if (b.category === 'peak') peak += len;
    if (b.category === 'quiet') quiet += len;
    sum += b.score;
  }
  return {
    duration: dur,
    peakSeconds: peak,
    quietSeconds: quiet,
    sceneChanges: sceneChangeCount,
    averageScore: sum / buckets.length,
  };
}