import * as plugins from './mod.plugins.js';
import { FormatContext } from './classes.formatcontext.js';
import { BaseFormatter } from './classes.baseformatter.js';
import type { IFormatPlan, IPlannedChange } from './interfaces.format.js';
import { logger } from '../gitzone.logging.js';
import { DependencyAnalyzer } from './classes.dependency-analyzer.js';
import { DiffReporter } from './classes.diffreporter.js';

export class FormatPlanner {
  private plannedChanges: Map<string, IPlannedChange[]> = new Map();
  private dependencyAnalyzer = new DependencyAnalyzer();
  private diffReporter = new DiffReporter();
  
  async planFormat(modules: BaseFormatter[]): Promise<IFormatPlan> {
    const plan: IFormatPlan = {
      summary: {
        totalFiles: 0,
        filesAdded: 0,
        filesModified: 0,
        filesRemoved: 0,
        estimatedTime: 0
      },
      changes: [],
      warnings: []
    };
    
    for (const module of modules) {
      try {
        const changes = await module.analyze();
        this.plannedChanges.set(module.name, changes);
        
        for (const change of changes) {
          plan.changes.push(change);
          
          // Update summary
          switch (change.type) {
            case 'create':
              plan.summary.filesAdded++;
              break;
            case 'modify':
              plan.summary.filesModified++;
              break;
            case 'delete':
              plan.summary.filesRemoved++;
              break;
          }
        }
      } catch (error) {
        plan.warnings.push({
          level: 'error',
          message: `Failed to analyze module ${module.name}: ${error.message}`,
          module: module.name
        });
      }
    }
    
    plan.summary.totalFiles = plan.summary.filesAdded + plan.summary.filesModified + plan.summary.filesRemoved;
    plan.summary.estimatedTime = plan.summary.totalFiles * 100; // 100ms per file estimate
    
    return plan;
  }
  
  async executePlan(plan: IFormatPlan, modules: BaseFormatter[], context: FormatContext, parallel: boolean = true): Promise<void> {
    await context.beginOperation();
    const startTime = Date.now();
    
    try {
      if (parallel) {
        // Get execution groups based on dependencies
        const executionGroups = this.dependencyAnalyzer.getExecutionGroups(modules);
        
        logger.log('info', `Executing formatters in ${executionGroups.length} groups...`);
        
        for (let i = 0; i < executionGroups.length; i++) {
          const group = executionGroups[i];
          logger.log('info', `Executing group ${i + 1}: ${group.map(m => m.name).join(', ')}`);
          
          // Execute modules in this group in parallel
          const promises = group.map(async (module) => {
            const changes = this.plannedChanges.get(module.name) || [];
            if (changes.length > 0) {
              logger.log('info', `Executing ${module.name} formatter...`);
              await module.execute(changes);
            }
          });
          
          await Promise.all(promises);
        }
      } else {
        // Sequential execution (original implementation)
        for (const module of modules) {
          const changes = this.plannedChanges.get(module.name) || [];
          
          if (changes.length > 0) {
            logger.log('info', `Executing ${module.name} formatter...`);
            await module.execute(changes);
          }
        }
      }
      
      const endTime = Date.now();
      const duration = endTime - startTime;
      logger.log('info', `Format operations completed in ${duration}ms`);
      
      await context.commitOperation();
    } catch (error) {
      await context.rollbackOperation();
      throw error;
    }
  }
  
  async displayPlan(plan: IFormatPlan, detailed: boolean = false): Promise<void> {
    console.log('\nFormat Plan:');
    console.log('━'.repeat(50));
    console.log(`Summary: ${plan.summary.totalFiles} files will be changed`);
    console.log(`  • ${plan.summary.filesAdded} new files`);
    console.log(`  • ${plan.summary.filesModified} modified files`);
    console.log(`  • ${plan.summary.filesRemoved} deleted files`);
    console.log('');
    console.log('Changes by module:');
    
    // Group changes by module
    const changesByModule = new Map<string, IPlannedChange[]>();
    for (const change of plan.changes) {
      const moduleChanges = changesByModule.get(change.module) || [];
      moduleChanges.push(change);
      changesByModule.set(change.module, moduleChanges);
    }
    
    for (const [module, changes] of changesByModule) {
      console.log(`\n${this.getModuleIcon(module)} ${module} (${changes.length} ${changes.length === 1 ? 'file' : 'files'})`);
      
      for (const change of changes) {
        const icon = this.getChangeIcon(change.type);
        console.log(`  ${icon} ${change.path} - ${change.description}`);
        
        // Show diff for modified files if detailed view is requested
        if (detailed && change.type === 'modify') {
          const diff = await this.diffReporter.generateDiffForChange(change);
          if (diff) {
            this.diffReporter.displayDiff(change.path, diff);
          }
        }
      }
    }
    
    if (plan.warnings.length > 0) {
      console.log('\nWarnings:');
      for (const warning of plan.warnings) {
        const icon = warning.level === 'error' ? '❌' : '⚠️';
        console.log(`  ${icon} ${warning.message}`);
      }
    }
    
    console.log('\n' + '━'.repeat(50));
  }
  
  private getModuleIcon(module: string): string {
    const icons: Record<string, string> = {
      'packagejson': '📦',
      'license': '📝',
      'tsconfig': '🔧',
      'cleanup': '🚮',
      'gitignore': '🔒',
      'prettier': '✨',
      'readme': '📖',
      'templates': '📄',
      'npmextra': '⚙️',
      'copy': '📋'
    };
    return icons[module] || '📁';
  }
  
  private getChangeIcon(type: 'create' | 'modify' | 'delete'): string {
    switch (type) {
      case 'create':
        return '✅';
      case 'modify':
        return '✏️';
      case 'delete':
        return '❌';
    }
  }
}