import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import * as fs from "fs";
import * as path from "path";
import * as yaml from "js-yaml";
import {
  DEFAULT_CONFIG,
  PRESET_PROFILES
} from "./types.js";
class ConfigManager {
  static instance = null;
  config;
  configPath;
  fileWatcher;
  onChangeCallbacks = [];
  constructor(configPath) {
    this.configPath = configPath || path.join(process.cwd(), ".stackmemory", "config.yaml");
    this.config = this.loadConfig();
  }
  /**
   * Get singleton instance of ConfigManager
   */
  static getInstance(configPath) {
    if (!ConfigManager.instance) {
      ConfigManager.instance = new ConfigManager(configPath);
    }
    return ConfigManager.instance;
  }
  /**
   * Load configuration from file or use defaults
   */
  loadConfig() {
    try {
      if (fs.existsSync(this.configPath)) {
        const content = fs.readFileSync(this.configPath, "utf-8");
        const loaded = yaml.load(content);
        return this.mergeWithDefaults(loaded);
      }
    } catch (error) {
      console.warn(`Failed to load config from ${this.configPath}:`, error);
    }
    return this.mergeWithDefaults({});
  }
  /**
   * Merge loaded config with defaults
   */
  mergeWithDefaults(loaded) {
    const config = {
      version: loaded.version || DEFAULT_CONFIG.version,
      profile: loaded.profile,
      scoring: {
        weights: {
          ...DEFAULT_CONFIG.scoring.weights,
          ...loaded.scoring?.weights
        },
        tool_scores: {
          ...DEFAULT_CONFIG.scoring.tool_scores,
          ...loaded.scoring?.tool_scores
        }
      },
      retention: {
        local: {
          ...DEFAULT_CONFIG.retention.local,
          ...loaded.retention?.local
        },
        remote: {
          ...DEFAULT_CONFIG.retention.remote,
          ...loaded.retention?.remote
        },
        generational_gc: {
          ...DEFAULT_CONFIG.retention.generational_gc,
          ...loaded.retention?.generational_gc
        }
      },
      performance: { ...DEFAULT_CONFIG.performance, ...loaded.performance },
      profiles: { ...PRESET_PROFILES, ...loaded.profiles }
    };
    if (config.profile && config.profiles?.[config.profile]) {
      this.applyProfile(config, config.profiles[config.profile]);
    }
    return config;
  }
  /**
   * Apply a profile to the configuration
   */
  applyProfile(config, profile) {
    if (profile.scoring) {
      if (profile.scoring.weights) {
        config.scoring.weights = {
          ...config.scoring.weights,
          ...profile.scoring.weights
        };
      }
      if (profile.scoring.tool_scores) {
        config.scoring.tool_scores = {
          ...config.scoring.tool_scores,
          ...profile.scoring.tool_scores
        };
      }
    }
    if (profile.retention) {
      if (profile.retention.local) {
        config.retention.local = {
          ...config.retention.local,
          ...profile.retention.local
        };
      }
      if (profile.retention.remote) {
        config.retention.remote = {
          ...config.retention.remote,
          ...profile.retention.remote
        };
      }
      if (profile.retention.generational_gc) {
        config.retention.generational_gc = {
          ...config.retention.generational_gc,
          ...profile.retention.generational_gc
        };
      }
    }
    if (profile.performance) {
      config.performance = { ...config.performance, ...profile.performance };
    }
  }
  /**
   * Validate configuration
   */
  validate() {
    const result = {
      valid: true,
      errors: [],
      warnings: [],
      suggestions: []
    };
    const weights = this.config.scoring.weights;
    const weightSum = weights.base + weights.impact + weights.persistence + weights.reference;
    if (Math.abs(weightSum - 1) > 1e-3) {
      result.errors.push(
        `Weights must sum to 1.0 (current: ${weightSum.toFixed(3)})`
      );
      result.valid = false;
    }
    Object.entries(weights).forEach(([key, value]) => {
      if (value < 0 || value > 1) {
        result.errors.push(
          `Weight ${key} must be between 0 and 1 (current: ${value})`
        );
        result.valid = false;
      }
    });
    Object.entries(this.config.scoring.tool_scores).forEach(([tool, score]) => {
      if (score !== void 0 && (score < 0 || score > 1)) {
        result.errors.push(
          `Tool score for ${tool} must be between 0 and 1 (current: ${score})`
        );
        result.valid = false;
      }
    });
    const youngMs = this.parseDuration(this.config.retention.local.young);
    const matureMs = this.parseDuration(this.config.retention.local.mature);
    const oldMs = this.parseDuration(this.config.retention.local.old);
    if (youngMs >= matureMs) {
      result.errors.push(
        "Young retention period must be less than mature period"
      );
      result.valid = false;
    }
    if (matureMs >= oldMs) {
      result.errors.push(
        "Mature retention period must be less than old period"
      );
      result.valid = false;
    }
    const maxSize = this.parseSize(this.config.retention.local.max_size);
    const availableSpace = this.getAvailableDiskSpace();
    if (availableSpace > 0 && maxSize > availableSpace) {
      result.warnings.push(
        `max_size (${this.config.retention.local.max_size}) exceeds available disk space`
      );
    }
    if (this.config.performance.retrieval_timeout_ms < 100) {
      result.warnings.push(
        "retrieval_timeout_ms < 100ms may be too aggressive"
      );
    }
    if (this.config.performance.max_stack_depth > 1e4) {
      result.warnings.push("max_stack_depth > 10000 may impact performance");
    }
    if (!this.config.profile) {
      result.suggestions.push("Consider using a profile for your use case");
    }
    if (this.config?.scoring?.tool_scores?.search && this.config.scoring.tool_scores.search < 0.5) {
      result.suggestions.push(
        "Search tool score seems low - consider increasing for better discovery"
      );
    }
    return result;
  }
  /**
   * Parse duration string to milliseconds
   */
  parseDuration(duration) {
    const match = duration.match(/^(\d+)([hdwm])$/);
    if (!match) return 0;
    const value = parseInt(match[1]);
    const unit = match[2];
    const multipliers = {
      h: 36e5,
      // hours
      d: 864e5,
      // days
      w: 6048e5,
      // weeks
      m: 2592e6
      // months (30 days)
    };
    return value * (multipliers[unit] || 0);
  }
  /**
   * Parse size string to bytes
   */
  parseSize(size) {
    const match = size.match(/^(\d+(?:\.\d+)?)([KMGT]B)?$/i);
    if (!match) return 0;
    const value = parseFloat(match[1]);
    const unit = match[2]?.toUpperCase() || "B";
    const multipliers = {
      B: 1,
      KB: 1024,
      MB: 1024 * 1024,
      GB: 1024 * 1024 * 1024,
      TB: 1024 * 1024 * 1024 * 1024
    };
    return value * (multipliers[unit] || 1);
  }
  /**
   * Get available disk space (simplified)
   */
  getAvailableDiskSpace() {
    return 0;
  }
  /**
   * Save configuration to file
   */
  save() {
    const dir = path.dirname(this.configPath);
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
    const content = yaml.dump(this.config, {
      indent: 2,
      lineWidth: 120,
      noRefs: true
    });
    fs.writeFileSync(this.configPath, content, "utf-8");
  }
  /**
   * Get current configuration
   */
  getConfig() {
    return { ...this.config };
  }
  /**
   * Get a specific configuration value by path
   * Example: config.get('project.id') returns config.project.id
   */
  get(path2) {
    const keys = path2.split(".");
    let value = this.config;
    for (const key of keys) {
      if (value && typeof value === "object" && key in value) {
        value = value[key];
      } else {
        return void 0;
      }
    }
    return value;
  }
  /**
   * Set active profile
   */
  setProfile(profileName) {
    const allProfiles = { ...PRESET_PROFILES, ...this.config.profiles };
    if (!allProfiles[profileName]) {
      return false;
    }
    this.config.profile = profileName;
    this.applyProfile(this.config, allProfiles[profileName]);
    this.notifyChange();
    return true;
  }
  /**
   * Update weights
   */
  updateWeights(weights) {
    this.config.scoring.weights = {
      ...this.config.scoring.weights,
      ...weights
    };
    this.notifyChange();
  }
  /**
   * Update tool scores
   */
  updateToolScores(scores) {
    this.config.scoring.tool_scores = {
      ...this.config.scoring.tool_scores,
      ...scores
    };
    this.notifyChange();
  }
  /**
   * Enable hot reload
   */
  enableHotReload() {
    if (this.fileWatcher) return;
    if (fs.existsSync(this.configPath)) {
      this.fileWatcher = fs.watch(this.configPath, (eventType) => {
        if (eventType === "change") {
          const newConfig = this.loadConfig();
          const validation = this.validate();
          if (validation.valid) {
            this.config = newConfig;
            this.notifyChange();
            console.log("Configuration reloaded");
          } else {
            console.error(
              "Invalid configuration, keeping previous:",
              validation.errors
            );
          }
        }
      });
    }
  }
  /**
   * Disable hot reload
   */
  disableHotReload() {
    if (this.fileWatcher) {
      this.fileWatcher.close();
      this.fileWatcher = void 0;
    }
  }
  /**
   * Register change callback
   */
  onChange(callback) {
    this.onChangeCallbacks.push(callback);
  }
  /**
   * Notify all change callbacks
   */
  notifyChange() {
    const config = this.getConfig();
    this.onChangeCallbacks.forEach((cb) => cb(config));
  }
  /**
   * Calculate importance score for a tool
   */
  calculateScore(tool, additionalFactors) {
    const baseScore = this.config.scoring.tool_scores[tool] || 0.5;
    const weights = this.config.scoring.weights;
    let score = baseScore * weights.base;
    if (additionalFactors) {
      if (additionalFactors.filesAffected !== void 0) {
        const impactMultiplier = Math.min(
          additionalFactors.filesAffected / 10,
          1
        );
        score += impactMultiplier * weights.impact;
      }
      if (additionalFactors.isPermanent) {
        score += 0.2 * weights.persistence;
      }
      if (additionalFactors.referenceCount !== void 0) {
        const refMultiplier = Math.min(
          additionalFactors.referenceCount / 100,
          1
        );
        score += refMultiplier * weights.reference;
      }
    }
    return Math.min(Math.max(score, 0), 1);
  }
  /**
   * Get available profiles
   */
  getProfiles() {
    return { ...PRESET_PROFILES, ...this.config.profiles };
  }
}
export {
  ConfigManager
};
//# sourceMappingURL=config-manager.js.map
