/**
 * TaskTimer - Countdown timer and reaction time measurement.
 */
class TaskTimer {
  /**
   * @param {number} durationSec - Total countdown time in seconds (0 = no countdown)
   * @param {function} onTick - Called each second with (remainingSec, formatted)
   * @param {function} onExpire - Called when timer reaches 0
   */
  constructor(durationSec, onTick, onExpire) {
    this.durationMs = durationSec * 1000;
    this.onTick = onTick || (() => {});
    this.onExpire = onExpire || (() => {});
    this.startTime = null;
    this.intervalId = null;
    this.running = false;
    this.expired = false;

    // RT measurement
    this._trialStart = null;
  }

  /** Start the countdown timer */
  start() {
    if (this.running) return;
    this.startTime = performance.now();
    this.running = true;
    this.expired = false;

    if (this.durationMs > 0) {
      this.intervalId = setInterval(() => this._tick(), 250);
      this._tick(); // Immediate first tick
    }
  }

  /** Pause the timer */
  pause() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
    this.running = false;
  }

  /** Stop and reset the timer */
  stop() {
    this.pause();
    this.startTime = null;
    this.expired = false;
  }

  /** Get remaining time in seconds */
  getRemainingSeconds() {
    if (!this.startTime || this.durationMs <= 0) return Infinity;
    const elapsed = performance.now() - this.startTime;
    return Math.max(0, Math.ceil((this.durationMs - elapsed) / 1000));
  }

  /** Get remaining time as MM:SS string */
  getFormattedRemaining() {
    const secs = this.getRemainingSeconds();
    if (secs === Infinity) return '--:--';
    const m = Math.floor(secs / 60);
    const s = secs % 60;
    return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
  }

  /** Check if time has expired */
  isExpired() {
    return this.expired;
  }

  // --- Reaction Time ---

  /** Mark the start of a trial for RT measurement */
  startTrial() {
    this._trialStart = performance.now();
  }

  /** Get reaction time in ms since startTrial() was called */
  getRT() {
    if (!this._trialStart) return null;
    return Math.round(performance.now() - this._trialStart);
  }

  /** Reset trial timer */
  resetTrial() {
    this._trialStart = null;
  }

  // Private

  _tick() {
    const remaining = this.getRemainingSeconds();
    this.onTick(remaining, this.getFormattedRemaining());

    if (remaining <= 0 && !this.expired) {
      this.expired = true;
      this.pause();
      this.onExpire();
    }
  }
}
