/**
 * Enhanced Progress Display
 * Multi-stage progress indicators with better visual feedback
 */

import chalk from 'chalk';
import * as output from './output';

export interface StageProgress {
  name: string;
  status: 'pending' | 'in-progress' | 'completed' | 'failed';
  current?: number;
  total?: number;
  message?: string;
  duration?: number;
}

export class EnhancedProgressDisplay {
  private stages: StageProgress[] = [];
  private startTime: number = Date.now();
  private lastRender: string = '';

  constructor(stages: string[]) {
    this.stages = stages.map(name => ({
      name,
      status: 'pending',
    }));
  }

  /**
   * Update a stage's progress
   */
  updateStage(stageName: string, update: Partial<StageProgress>): void {
    const stage = this.stages.find(s => s.name === stageName);
    if (stage) {
      Object.assign(stage, update);
      this.render();
    }
  }

  /**
   * Mark a stage as in progress
   */
  startStage(stageName: string, total?: number): void {
    this.updateStage(stageName, {
      status: 'in-progress',
      current: 0,
      total,
      message: undefined,
    });
  }

  /**
   * Update progress within a stage
   */
  updateProgress(stageName: string, current: number, message?: string): void {
    this.updateStage(stageName, { current, message });
  }

  /**
   * Complete a stage
   */
  completeStage(stageName: string, message?: string): void {
    const stage = this.stages.find(s => s.name === stageName);
    if (stage) {
      const duration = stage.status === 'in-progress' ? Date.now() - this.startTime : undefined;
      this.updateStage(stageName, {
        status: 'completed',
        message,
        duration,
      });
    }
  }

  /**
   * Fail a stage
   */
  failStage(stageName: string, message?: string): void {
    this.updateStage(stageName, {
      status: 'failed',
      message,
    });
  }

  /**
   * Render the progress display
   */
  private render(): void {
    const lines: string[] = [];

    // Calculate overall progress
    const completed = this.stages.filter(s => s.status === 'completed').length;
    const total = this.stages.length;
    const percentage = Math.round((completed / total) * 100);

    // Overall progress bar
    lines.push('');
    lines.push(chalk.bold('Progress:') + ' ' + this.renderProgressBar(completed, total) + ' ' + chalk.cyan(`${percentage}%`));
    lines.push('');

    // Render each stage
    for (const stage of this.stages) {
      lines.push(this.renderStage(stage));
    }

    // Elapsed time
    const elapsed = Math.round((Date.now() - this.startTime) / 1000);
    lines.push('');
    lines.push(chalk.gray(`Elapsed: ${this.formatDuration(elapsed)}`));

    // Clear previous render and display new one
    const rendered = lines.join('\n');
    if (rendered !== this.lastRender) {
      // Move cursor up to overwrite previous render
      if (this.lastRender) {
        const lineCount = this.lastRender.split('\n').length;
        process.stdout.write(`\x1b[${lineCount}A`);
      }

      process.stdout.write(rendered + '\n');
      this.lastRender = rendered;
    }
  }

  /**
   * Render a single stage
   */
  private renderStage(stage: StageProgress): string {
    let icon: string;
    let color: (text: string) => string;

    switch (stage.status) {
      case 'completed':
        icon = '✓';
        color = chalk.green;
        break;
      case 'in-progress':
        icon = '◐';
        color = chalk.cyan;
        break;
      case 'failed':
        icon = '✗';
        color = chalk.red;
        break;
      default:
        icon = '○';
        color = chalk.gray;
    }

    let line = '  ' + color(icon) + ' ' + stage.name;

    // Add progress within stage
    if (stage.status === 'in-progress' && stage.total) {
      const current = stage.current || 0;
      const stagePercentage = Math.round((current / stage.total) * 100);
      line += ' ' + chalk.gray(`(${current}/${stage.total}) ${stagePercentage}%`);
    }

    // Add duration for completed stages
    if (stage.status === 'completed' && stage.duration) {
      const duration = Math.round(stage.duration / 1000);
      line += ' ' + chalk.gray(`[${this.formatDuration(duration)}]`);
    }

    // Add message
    if (stage.message) {
      line += '\n    ' + chalk.gray(stage.message);
    }

    return line;
  }

  /**
   * Render a progress bar
   */
  private renderProgressBar(current: number, total: number): string {
    const width = 30;
    const filled = Math.round((current / total) * width);
    const empty = width - filled;

    return chalk.green('█'.repeat(filled)) + chalk.gray('░'.repeat(empty));
  }

  /**
   * Format duration in human-readable format
   */
  private formatDuration(seconds: number): string {
    if (seconds < 60) {
      return `${seconds}s`;
    }

    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins}m ${secs}s`;
  }

  /**
   * Final summary
   */
  renderSummary(): void {
    output.blank();
    output.header('Summary');

    const _completed = this.stages.filter(s => s.status === 'completed').length;
    const failed = this.stages.filter(s => s.status === 'failed').length;
    const total = this.stages.length;

    if (failed > 0) {
      output.error(`${failed} stage(s) failed`);
    } else {
      output.success(`All ${total} stages completed successfully`);
    }

    const totalDuration = Math.round((Date.now() - this.startTime) / 1000);
    output.info(`Total time: ${this.formatDuration(totalDuration)}`);

    output.blank();
  }
}

/**
 * Create a simple stage-based progress tracker
 */
export function createStageProgress(stages: string[]): EnhancedProgressDisplay {
  return new EnhancedProgressDisplay(stages);
}
