import * as plugins from './mod.plugins.js';
import { FormatContext } from './classes.formatcontext.js';
import type { IPlannedChange } from './interfaces.format.js';
import { Project } from '../classes.project.js';
import { ChangeCache } from './classes.changecache.js';

export abstract class BaseFormatter {
  protected context: FormatContext;
  protected project: Project;
  protected cache: ChangeCache;
  protected stats: any; // Will be FormatStats from context
  
  constructor(context: FormatContext, project: Project) {
    this.context = context;
    this.project = project;
    this.cache = context.getChangeCache();
    this.stats = context.getFormatStats();
  }
  
  abstract get name(): string;
  abstract analyze(): Promise<IPlannedChange[]>;
  abstract applyChange(change: IPlannedChange): Promise<void>;
  
  async execute(changes: IPlannedChange[]): Promise<void> {
    const startTime = this.stats.moduleStartTime(this.name);
    this.stats.startModule(this.name);
    
    try {
      await this.preExecute();
      
      for (const change of changes) {
        try {
          await this.applyChange(change);
          this.stats.recordFileOperation(this.name, change.type, true);
        } catch (error) {
          this.stats.recordFileOperation(this.name, change.type, false);
          throw error;
        }
      }
      
      await this.postExecute();
    } catch (error) {
      await this.context.rollbackOperation();
      throw error;
    } finally {
      this.stats.endModule(this.name, startTime);
    }
  }
  
  protected async preExecute(): Promise<void> {
    // Override in subclasses if needed
  }
  
  protected async postExecute(): Promise<void> {
    // Override in subclasses if needed
  }
  
  protected async modifyFile(filepath: string, content: string): Promise<void> {
    await this.context.trackFileChange(filepath);
    await plugins.smartfile.memory.toFs(content, filepath);
    await this.cache.updateFileCache(filepath);
  }
  
  protected async createFile(filepath: string, content: string): Promise<void> {
    await plugins.smartfile.memory.toFs(content, filepath);
    await this.cache.updateFileCache(filepath);
  }
  
  protected async deleteFile(filepath: string): Promise<void> {
    await this.context.trackFileChange(filepath);
    await plugins.smartfile.fs.remove(filepath);
  }
  
  protected async shouldProcessFile(filepath: string): Promise<boolean> {
    const config = new plugins.npmextra.Npmextra();
    const useCache = config.dataFor('gitzone.format.cache.enabled', true);
    
    if (!useCache) {
      return true; // Process all files if cache is disabled
    }
    
    const hasChanged = await this.cache.hasFileChanged(filepath);
    
    // Record cache statistics
    if (hasChanged) {
      this.stats.recordCacheMiss();
    } else {
      this.stats.recordCacheHit();
    }
    
    return hasChanged;
  }
}