import { BaseFormatter } from '../classes.baseformatter.js';
import type { IPlannedChange } from '../interfaces.format.js';
import * as plugins from '../mod.plugins.js';
import { logger, logVerbose } from '../../gitzone.logging.js';

export class PrettierFormatter extends BaseFormatter {
  get name(): string {
    return 'prettier';
  }
  
  async analyze(): Promise<IPlannedChange[]> {
    const changes: IPlannedChange[] = [];
    const globPattern = '**/*.{ts,tsx,js,jsx,json,md,css,scss,html,xml,yaml,yml}';
    
    // Get all files that match the pattern
    const files = await plugins.smartfile.fs.listFileTree('.', globPattern);
    
    // Check which files need formatting
    for (const file of files) {
      // Skip files that haven't changed
      if (!await this.shouldProcessFile(file)) {
        logVerbose(`Skipping ${file} - no changes detected`);
        continue;
      }
      
      changes.push({
        type: 'modify',
        path: file,
        module: this.name,
        description: 'Format with Prettier'
      });
    }
    
    logger.log('info', `Found ${changes.length} files to format with Prettier`);
    return changes;
  }
  
  async execute(changes: IPlannedChange[]): Promise<void> {
    const startTime = this.stats.moduleStartTime(this.name);
    this.stats.startModule(this.name);
    
    try {
      await this.preExecute();
      
      // Batch process files
      const batchSize = 10; // Process 10 files at a time
      const batches: IPlannedChange[][] = [];
      
      for (let i = 0; i < changes.length; i += batchSize) {
        batches.push(changes.slice(i, i + batchSize));
      }
      
      logVerbose(`Processing ${changes.length} files in ${batches.length} batches`);
      
      for (let i = 0; i < batches.length; i++) {
        const batch = batches[i];
        logVerbose(`Processing batch ${i + 1}/${batches.length} (${batch.length} files)`);
        
        // Process batch in parallel
        const promises = batch.map(async (change) => {
          try {
            await this.applyChange(change);
            this.stats.recordFileOperation(this.name, change.type, true);
          } catch (error) {
            this.stats.recordFileOperation(this.name, change.type, false);
            logger.log('error', `Failed to format ${change.path}: ${error.message}`);
            // Don't throw - continue with other files
          }
        });
        
        await Promise.all(promises);
      }
      
      await this.postExecute();
    } catch (error) {
      await this.context.rollbackOperation();
      throw error;
    } finally {
      this.stats.endModule(this.name, startTime);
    }
  }
  
  async applyChange(change: IPlannedChange): Promise<void> {
    if (change.type !== 'modify') return;
    
    try {
      // Read current content
      const content = await plugins.smartfile.fs.toStringSync(change.path);
      
      // Format with prettier
      const prettier = await import('prettier');
      const formatted = await prettier.format(content, {
        filepath: change.path,
        ...(await this.getPrettierConfig())
      });
      
      // Only write if content actually changed
      if (formatted !== content) {
        await this.modifyFile(change.path, formatted);
        logVerbose(`Formatted ${change.path}`);
      } else {
        // Still update cache even if content didn't change
        await this.cache.updateFileCache(change.path);
        logVerbose(`No formatting changes for ${change.path}`);
      }
    } catch (error) {
      logger.log('error', `Failed to format ${change.path}: ${error.message}`);
      throw error;
    }
  }
  
  private async getPrettierConfig(): Promise<any> {
    // Try to load prettier config from the project
    const prettierConfig = new plugins.npmextra.Npmextra();
    return prettierConfig.dataFor('prettier', {
      // Default prettier config
      singleQuote: true,
      trailingComma: 'all',
      printWidth: 80,
      tabWidth: 2,
      semi: true,
      arrowParens: 'always'
    });
  }
}