import type { ITapSettings, ISettingsManager } from './tapbundle.interfaces.js';

export class SettingsManager implements ISettingsManager {
  private globalSettings: ITapSettings = {};
  private fileSettings: ITapSettings = {};
  private testSettings: Map<string, ITapSettings> = new Map();
  
  // Default settings
  private defaultSettings: ITapSettings = {
    timeout: undefined, // No timeout by default
    slowThreshold: 1000, // 1 second
    bail: false,
    retries: 0,
    retryDelay: 0,
    suppressConsole: false,
    verboseErrors: true,
    showTestDuration: true,
    maxConcurrency: 5,
    isolateTests: false,
    enableSnapshots: true,
    snapshotDirectory: '.snapshots',
    updateSnapshots: false,
  };

  /**
   * Get merged settings for current context
   */
  public getSettings(): ITapSettings {
    return this.mergeSettings(
      this.defaultSettings,
      this.globalSettings,
      this.fileSettings
    );
  }

  /**
   * Set global settings (from 00init.ts or tap.settings())
   */
  public setGlobalSettings(settings: ITapSettings): void {
    this.globalSettings = { ...this.globalSettings, ...settings };
  }

  /**
   * Set file-level settings
   */
  public setFileSettings(settings: ITapSettings): void {
    this.fileSettings = { ...this.fileSettings, ...settings };
  }

  /**
   * Set test-specific settings
   */
  public setTestSettings(testId: string, settings: ITapSettings): void {
    const existingSettings = this.testSettings.get(testId) || {};
    this.testSettings.set(testId, { ...existingSettings, ...settings });
  }

  /**
   * Get settings for specific test
   */
  public getTestSettings(testId: string): ITapSettings {
    const testSpecificSettings = this.testSettings.get(testId) || {};
    return this.mergeSettings(
      this.defaultSettings,
      this.globalSettings,
      this.fileSettings,
      testSpecificSettings
    );
  }

  /**
   * Merge settings with proper inheritance
   * Later settings override earlier ones
   */
  private mergeSettings(...settingsArray: ITapSettings[]): ITapSettings {
    const result: ITapSettings = {};

    for (const settings of settingsArray) {
      // Simple properties - later values override
      if (settings.timeout !== undefined) result.timeout = settings.timeout;
      if (settings.slowThreshold !== undefined) result.slowThreshold = settings.slowThreshold;
      if (settings.bail !== undefined) result.bail = settings.bail;
      if (settings.retries !== undefined) result.retries = settings.retries;
      if (settings.retryDelay !== undefined) result.retryDelay = settings.retryDelay;
      if (settings.suppressConsole !== undefined) result.suppressConsole = settings.suppressConsole;
      if (settings.verboseErrors !== undefined) result.verboseErrors = settings.verboseErrors;
      if (settings.showTestDuration !== undefined) result.showTestDuration = settings.showTestDuration;
      if (settings.maxConcurrency !== undefined) result.maxConcurrency = settings.maxConcurrency;
      if (settings.isolateTests !== undefined) result.isolateTests = settings.isolateTests;
      if (settings.enableSnapshots !== undefined) result.enableSnapshots = settings.enableSnapshots;
      if (settings.snapshotDirectory !== undefined) result.snapshotDirectory = settings.snapshotDirectory;
      if (settings.updateSnapshots !== undefined) result.updateSnapshots = settings.updateSnapshots;

      // Lifecycle hooks - later ones override
      if (settings.beforeAll !== undefined) result.beforeAll = settings.beforeAll;
      if (settings.afterAll !== undefined) result.afterAll = settings.afterAll;
      if (settings.beforeEach !== undefined) result.beforeEach = settings.beforeEach;
      if (settings.afterEach !== undefined) result.afterEach = settings.afterEach;

      // Environment variables - merge
      if (settings.env) {
        result.env = { ...result.env, ...settings.env };
      }
    }

    return result;
  }

  /**
   * Clear all settings (useful for testing)
   */
  public clearSettings(): void {
    this.globalSettings = {};
    this.fileSettings = {};
    this.testSettings.clear();
  }
}