/**
 * @moduleName: TimerService
 * @version: 1.0.0
 * @since: 2025-07-24
 * @lastUpdated: 2025-07-24
 * @projectSummary: Quiz timing functionality with configurable time limits and pressure mode
 * @techStack: TypeScript, DOM API, Local Storage
 * @dependency: None
 * @interModuleDependency: SettingsService.ts, AppStore.ts
 * @requirementsTraceability: ISSUE_005 (Top Status Bar Implementation), ISSUE_013 (Quiz Timing Features)
 * @briefDescription: Manages quiz timers, time pressure features, and timing-related UI updates
 * @methods: startTimer, stopTimer, pauseTimer, getTimeRemaining, formatTime, isTimerEnabled
 * @contributors: GitHub Copilot
 * @examples: const timer = TimerService.getInstance(); timer.startTimer(300); // 5 minutes
 * @vulnerabilitiesAssessment: No security concerns - client-side timing only, validation on server
 */

export interface TimerSettings {
  enabled: boolean;
  duration: number; // in seconds
  warning: number; // seconds before end to show warning
  autoSubmit: boolean; // auto-submit when time expires
}

export interface TimerState {
  isRunning: boolean;
  timeRemaining: number;
  totalTime: number;
  isWarning: boolean;
  isExpired: boolean;
}

export class TimerService {
  private static instance: TimerService;
  private timerState: TimerState;
  private intervalId: NodeJS.Timeout | null = null;
  private callbacks: Array<(state: TimerState) => void> = [];
  private timerDisplay: HTMLElement | null = null;
  private timerContainer: HTMLElement | null = null;
  private warningThreshold: number = 60; // default warning threshold in seconds
  private timerToggle: HTMLInputElement | null = null;

  private constructor() {
    this.timerState = {
      isRunning: false,
      timeRemaining: 0,
      totalTime: 0,
      isWarning: false,
      isExpired: false,
    };

    this.initializeDOM();
  }

  /**
   * @description Gets the singleton instance of TimerService
   * @returns {TimerService} The singleton TimerService instance
   */
  public static getInstance(): TimerService {
    if (!TimerService.instance) {
      TimerService.instance = new TimerService();
    }
    return TimerService.instance;
  }

  private initializeDOM(): void {
    this.timerDisplay = document.querySelector('#timer-display');
    this.timerContainer = document.querySelector('#quiz-timer');

    // Setup timer toggle
    this.timerToggle = document.querySelector('#timer-toggle') as HTMLInputElement;
    if (this.timerToggle) {
      this.timerToggle.addEventListener('change', e => {
        const enabled = (e.target as HTMLInputElement).checked;
        this.toggleTimer(enabled);
      });
    }
  }

  /**
   * @description Subscribes to timer state changes
   * @param {function} callback Function to call when timer state changes
   * @returns {function} Unsubscribe function to remove the callback
   */
  public subscribe(callback: (state: TimerState) => void): () => void {
    this.callbacks.push(callback);
    return () => {
      const index = this.callbacks.indexOf(callback);
      if (index > -1) {
        this.callbacks.splice(index, 1);
      }
    };
  }

  private notifySubscribers(): void {
    this.callbacks.forEach(callback => callback(this.timerState));
  }

  /**
   * @description Starts the quiz timer with specified duration
   * @param {number} durationInSeconds Timer duration in seconds (default: 300)
   * @param {number} warningThreshold Warning threshold in seconds (default: 60)
   */
  public startTimer(durationInSeconds: number = 300, warningThreshold: number = 60): void {
    this.stopTimer(); // Clear any existing timer

    this.warningThreshold = warningThreshold;

    this.timerState = {
      isRunning: true,
      timeRemaining: durationInSeconds,
      totalTime: durationInSeconds,
      isWarning: false,
      isExpired: false,
    };

    this.showTimer();
    this.updateDisplay();

    this.intervalId = setInterval(() => {
      this.tick();
    }, 1000);

    this.notifySubscribers();
  }

  /**
   * @description Stops the timer and clears all intervals
   */
  public stopTimer(): void {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }

    this.timerState.isRunning = false;
    this.hideTimer();
    this.notifySubscribers();
  }

  public pauseTimer(): void {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
    this.timerState.isRunning = false;
    this.notifySubscribers();
  }

  public resumeTimer(): void {
    if (!this.timerState.isExpired && this.timerState.timeRemaining > 0) {
      this.timerState.isRunning = true;
      this.intervalId = setInterval(() => {
        this.tick();
      }, 1000);
      this.notifySubscribers();
    }
  }

  private tick(): void {
    this.timerState.timeRemaining -= 1;

    // Check for warning state using the configurable threshold
    this.timerState.isWarning = this.timerState.timeRemaining <= this.warningThreshold;

    // Check for expiration
    if (this.timerState.timeRemaining <= 0) {
      this.timerState.timeRemaining = 0;
      this.timerState.isExpired = true;
      this.timerState.isRunning = false;
      this.stopTimer();

      // Auto-submit if enabled
      this.handleTimeExpiry();
    }

    this.updateDisplay();
    this.notifySubscribers();
  }

  private handleTimeExpiry(): void {
    // Retrieve TimerSettings from localStorage or a settings service
    let autoSubmit = false;
    try {
      const settingsStr = localStorage.getItem('timerSettings');
      if (settingsStr) {
        const settings: TimerSettings = JSON.parse(settingsStr);
        autoSubmit = settings.autoSubmit;
      }
    } catch (e) {
      // Fallback: do not auto-submit if settings are not available
      autoSubmit = false;
    }

    const submitButton = document.querySelector('#submit-button') as HTMLButtonElement;
    if (submitButton) {
      // Show time expired message
      this.showTimeExpiredMessage();

      if (autoSubmit) {
        // Auto-submit after a short delay to let user see the message
        setTimeout(() => {
          submitButton.click();
        }, 2000);
      }
    }
  }

  private showTimeExpiredMessage(): void {
    const message = document.createElement('div');
    message.className =
      'fixed top-20 left-1/2 transform -translate-x-1/2 bg-red-500 text-white px-6 py-3 rounded-lg shadow-lg z-50 animate-bounce';
    message.textContent =
      "⏰ Time's up! " +
      (this.getAutoSubmitSetting() ? 'Submitting quiz...' : 'Please submit your quiz.');
    document.body.appendChild(message);

    setTimeout(() => {
      if (document.body.contains(message)) {
        document.body.removeChild(message);
      }
    }, 3000);
  }

  private getAutoSubmitSetting(): boolean {
    try {
      const settingsStr = localStorage.getItem('timerSettings');
      if (settingsStr) {
        const settings: TimerSettings = JSON.parse(settingsStr);
        return settings.autoSubmit;
      }
    } catch (e) {
      // Fallback
    }
    return false;
  }

  private updateDisplay(): void {
    if (this.timerDisplay) {
      this.timerDisplay.textContent = this.formatTime(this.timerState.timeRemaining);

      // Update styling based on state
      if (this.timerState.isWarning) {
        this.timerDisplay.classList.add('text-red-500', 'font-bold', 'animate-pulse');
      } else {
        this.timerDisplay.classList.remove('text-red-500', 'font-bold', 'animate-pulse');
      }
    }
  }

  private showTimer(): void {
    if (this.timerContainer) {
      this.timerContainer.classList.remove('hidden');
      this.timerContainer.classList.add('flex');
    }
  }

  private hideTimer(): void {
    if (this.timerContainer) {
      this.timerContainer.classList.add('hidden');
      this.timerContainer.classList.remove('flex');
    }
  }

  private toggleTimer(enabled: boolean): void {
    if (enabled) {
      // Start timer with default 5 minutes (300 seconds) and default warning threshold
      this.startTimer(300, this.warningThreshold);
    } else {
      this.stopTimer();
    }
  }

  /**
   * @description Formats seconds into MM:SS format
   * @param {number} seconds Time in seconds to format
   * @returns {string} Formatted time string (MM:SS)
   */
  public formatTime(seconds: number): string {
    const minutes = Math.floor(seconds / 60);
    const remainingSeconds = seconds % 60;
    return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
  }

  /**
   * @description Gets current timer state
   * @returns {TimerState} Copy of current timer state
   */
  public getState(): TimerState {
    return { ...this.timerState };
  }

  public isTimerEnabled(): boolean {
    return this.timerToggle?.checked || false;
  }

  public getTimeRemaining(): number {
    return this.timerState.timeRemaining;
  }

  public getProgressPercentage(): number {
    if (this.timerState.totalTime === 0) return 0;
    return (
      ((this.timerState.totalTime - this.timerState.timeRemaining) / this.timerState.totalTime) *
      100
    );
  }

  // Additional utility methods for enhanced functionality
  public setWarningThreshold(seconds: number): void {
    this.warningThreshold = seconds;
  }

  public getWarningThreshold(): number {
    return this.warningThreshold;
  }

  public saveTimerSettings(settings: TimerSettings): void {
    try {
      localStorage.setItem('timerSettings', JSON.stringify(settings));
    } catch (e) {
      console.warn('Failed to save timer settings:', e);
    }
  }

  public loadTimerSettings(): TimerSettings {
    try {
      const settingsStr = localStorage.getItem('timerSettings');
      if (settingsStr) {
        return JSON.parse(settingsStr);
      }
    } catch (e) {
      console.warn('Failed to load timer settings:', e);
    }

    // Return default settings
    return {
      enabled: false,
      duration: 300, // 5 minutes
      warning: 60, // 1 minute warning
      autoSubmit: false,
    };
  }
}
