// services/web-ui/public/js/timecode.js
// 59.94 fps drop-frame timecode utilities.
// Exposes: window.TC

(function (global) {
  'use strict';

  // 59.94 = 60000/1001
  const FPS_EXACT        = 60000 / 1001;
  const NOM              = 60;   // nominal integer fps
  const DROP             = 4;    // frames dropped per minute (except every 10th)
  const FRAMES_FIRST_MIN = NOM * 60;                    // 3600 – non-drop minute
  const FRAMES_PER_MIN   = NOM * 60 - DROP;             // 3596 – drop minute
  const FRAMES_PER_10MIN = FRAMES_PER_MIN * 10 + DROP;  // 35964
  const FRAMES_PER_HOUR  = FRAMES_PER_10MIN * 6;        // 215784

  function pad2(n) { return String(Math.floor(n)).padStart(2, '0'); }

  /**
   * Convert a frame count to a 59.94 DF timecode string: HH:MM:SS;FF
   *
   * Each 10-minute group contains one non-drop minute (3600 frames) followed
   * by nine drop minutes (3596 frames each).  Frame numbers 0–3 are skipped at
   * the start of every drop minute; we account for this by shifting the
   * within-minute frame index by DROP when computing ss/ff.
   */
  function framesToTC(totalFrames) {
    const fc  = Math.max(0, Math.round(totalFrames));
    const h   = Math.floor(fc / FRAMES_PER_HOUR);
    let rem   = fc % FRAMES_PER_HOUR;
    const tm  = Math.floor(rem / FRAMES_PER_10MIN); // tens-of-minutes group (0–5)
    rem       = rem % FRAMES_PER_10MIN;

    let m, ss, ff;
    if (rem < FRAMES_FIRST_MIN) {
      // First minute of the 10-min group — no frame drop
      m  = 0;
      ss = Math.floor(rem / NOM);
      ff = rem % NOM;
    } else {
      // Minutes 1–9: frame numbers 0–3 at second :00 are skipped
      rem -= FRAMES_FIRST_MIN;
      m   = Math.floor(rem / FRAMES_PER_MIN) + 1;
      const remInMin = rem % FRAMES_PER_MIN;
      // Shift by DROP so the label starts at :00;04 instead of :00;00
      const adj = remInMin + DROP;
      ss  = Math.floor(adj / NOM);
      ff  = adj % NOM;
    }
    const M = tm * 10 + m;
    return `${pad2(h)}:${pad2(M)}:${pad2(ss)};${pad2(ff)}`;
  }

  /**
   * Convert a 59.94 DF timecode string (HH:MM:SS;FF or HH:MM:SS:FF) to frame count.
   */
  function tcToFrames(tc) {
    if (!tc) return 0;
    const clean = String(tc).replace(';', ':');
    const parts = clean.split(':').map(Number);
    if (parts.length !== 4) return 0;
    const [h, m, s, f] = parts;
    const totalMinutes = h * 60 + m;
    return (NOM * 3600 * h)
         + (NOM * 60   * m)
         + (NOM        * s)
         +  f
         - DROP * (totalMinutes - Math.floor(totalMinutes / 10));
  }

  /**
   * Convert seconds (float) → frame count at 59.94.
   */
  function secondsToFrames(seconds) {
    return Math.round(seconds * FPS_EXACT);
  }

  /**
   * Convert frame count → seconds (float) at 59.94.
   */
  function framesToSeconds(frames) {
    return frames / FPS_EXACT;
  }

  global.TC = {
    framesToTC,
    tcToFrames,
    secondsToFrames,
    framesToSeconds,
    FPS: FPS_EXACT,
  };

})(window);
