/**
 * NeuroLink Config Manager with Backup/Restore System
 * Industry standard configuration management with safety mechanisms
 */
import { promises as fs } from "fs";
import { join } from "path";
import { createHash } from "crypto";
import { logger } from "../utils/logger.js";
import { DEFAULT_CONFIG } from "../types/configTypes.js";
const { readFile, writeFile, readdir, mkdir, unlink, access } = fs;
/**
 * Enhanced Config Manager with automatic backup/restore capabilities
 */
export class NeuroLinkConfigManager {
    configPath = ".neurolink.config";
    backupDir = ".neurolink.backups";
    config = null;
    configCache = new Map();
    /**
     * Load configuration with caching
     */
    async loadConfig() {
        if (!this.config) {
            this.config = await this.readConfigFile();
        }
        return this.config;
    }
    /**
     * Update configuration with automatic backup
     */
    async updateConfig(updates, options = {}) {
        const { createBackup = true, validate = true, merge = true, reason = "update", silent = false, } = options;
        // ALWAYS create backup before updating (unless explicitly disabled)
        if (createBackup) {
            await this.createBackup(reason);
            if (!silent) {
                logger.info("💾 Backup created before config update");
            }
        }
        const existing = await this.loadConfig();
        // Merge or replace based on options
        this.config = merge
            ? { ...existing, ...updates, lastUpdated: Date.now() }
            : { ...updates, lastUpdated: Date.now() };
        // Validate config if requested
        if (validate) {
            const validation = await this.validateConfig(this.config);
            if (!validation.valid) {
                throw new Error(`Config validation failed: ${validation.errors.join(", ")}`);
            }
        }
        try {
            await this.persistConfig(this.config);
            if (!silent) {
                logger.info("✅ Configuration updated successfully");
            }
        }
        catch (error) {
            // Auto-restore on failure
            if (createBackup) {
                await this.restoreLatestBackup();
                if (!silent) {
                    logger.info("🔄 Auto-restored from backup due to error");
                }
            }
            throw new Error(`Config update failed, restored from backup: ${error.message}`, { cause: error });
        }
    }
    /**
     * Create a backup with metadata
     */
    async createBackup(reason = "manual") {
        await this.ensureBackupDirectory();
        const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
        const backupFilename = `neurolink-config-${timestamp}.js`;
        const backupPath = join(this.backupDir, backupFilename);
        const currentConfig = await this.loadConfig();
        const configHash = this.generateConfigHash(currentConfig);
        const backupMetadata = {
            reason,
            timestamp: Date.now(),
            version: currentConfig.configVersion || "unknown",
            originalPath: this.configPath,
            hash: configHash,
            size: JSON.stringify(currentConfig).length,
            createdBy: "NeuroLinkConfigManager",
        };
        const backupContent = `// NeuroLink Config Backup - ${reason}
// Created: ${new Date().toISOString()}
// Reason: ${reason}
// Hash: ${configHash}
export const metadata = ${JSON.stringify(backupMetadata, null, 2)};
export default ${JSON.stringify(currentConfig, null, 2)};`;
        await writeFile(backupPath, backupContent, "utf-8");
        return backupPath;
    }
    /**
     * List all available backups
     */
    async listBackups() {
        await this.ensureBackupDirectory();
        try {
            const files = await readdir(this.backupDir);
            const backupFiles = files.filter((f) => f.startsWith("neurolink-config-") && f.endsWith(".js"));
            const backups = [];
            for (const file of backupFiles) {
                try {
                    const filePath = join(this.backupDir, file);
                    const content = await readFile(filePath, "utf-8");
                    const metadata = this.extractMetadataFromBackup(content);
                    const config = this.extractConfigFromBackup(content);
                    backups.push({
                        filename: file,
                        path: filePath,
                        metadata,
                        config,
                    });
                }
                catch (error) {
                    logger.warn(`Failed to read backup ${file}:`, error.message);
                }
            }
            return backups.sort((a, b) => b.metadata.timestamp - a.metadata.timestamp);
        }
        catch (error) {
            logger.warn("Failed to list backups:", error.message);
            return [];
        }
    }
    /**
     * Restore from specific backup
     */
    async restoreFromBackup(backupFilename) {
        const backupPath = join(this.backupDir, backupFilename);
        // Create backup of current config before restore
        await this.createBackup("pre-restore");
        try {
            const content = await readFile(backupPath, "utf-8");
            const restoredConfig = this.extractConfigFromBackup(content);
            // Validate restored config
            const validation = await this.validateConfig(restoredConfig);
            if (!validation.valid) {
                throw new Error(`Backup config is invalid: ${validation.errors.join(", ")}`);
            }
            this.config = restoredConfig;
            await this.persistConfig(this.config);
            logger.info(`✅ Config restored from backup: ${backupFilename}`);
        }
        catch (error) {
            throw new Error(`Failed to restore from backup ${backupFilename}: ${error.message}`, { cause: error });
        }
    }
    /**
     * Restore from latest backup
     */
    async restoreLatestBackup() {
        const backups = await this.listBackups();
        if (backups.length === 0) {
            throw new Error("No backups available for restore");
        }
        await this.restoreFromBackup(backups[0].filename);
    }
    /**
     * Clean up old backups
     */
    async cleanupOldBackups(keepCount = 10) {
        const backups = await this.listBackups();
        const toDelete = backups.slice(keepCount);
        for (const backup of toDelete) {
            try {
                await unlink(backup.path);
                logger.info(`🗑️ Deleted old backup: ${backup.filename}`);
            }
            catch (error) {
                logger.warn(`Failed to delete backup ${backup.filename}:`, error.message);
            }
        }
    }
    /**
     * Update provider status
     */
    async updateProviderStatus(providerId, status) {
        const config = await this.loadConfig();
        if (!config.providers) {
            config.providers = {};
        }
        config.providers[providerId] = {
            ...config.providers[providerId],
            ...status,
            lastCheck: Date.now(),
        };
        await this.updateConfig({ providers: config.providers }, { reason: `provider-${providerId}-update` });
    }
    /**
     * Validate configuration
     */
    async validateConfig(config) {
        const result = {
            valid: true,
            errors: [],
            warnings: [],
            suggestions: [],
        };
        // Basic validation
        if (!config || typeof config !== "object") {
            result.errors.push("Config must be a valid object");
            result.valid = false;
            return result;
        }
        // Version validation
        if (config.configVersion && typeof config.configVersion !== "string") {
            result.errors.push("configVersion must be a string");
            result.valid = false;
        }
        // Provider validation
        if (config.providers) {
            if (typeof config.providers !== "object") {
                result.errors.push("providers must be an object");
                result.valid = false;
            }
            else {
                // Check for default provider
                if (!config.providers.defaultProvider) {
                    result.warnings.push("No default provider specified");
                    result.suggestions.push('Consider setting providers.defaultProvider to "googleAi"');
                }
            }
        }
        // Performance validation
        if (config.performance?.cache?.ttlMs) {
            if (config.performance.cache.ttlMs < 1000) {
                result.warnings.push("Cache TTL is very low (< 1 second)");
            }
        }
        return result;
    }
    /**
     * Generate default configuration
     */
    async generateDefaultConfig() {
        return {
            ...DEFAULT_CONFIG,
            lastUpdated: Date.now(),
        };
    }
    // Private helper methods
    async ensureBackupDirectory() {
        try {
            await mkdir(this.backupDir, { recursive: true });
        }
        catch (error) {
            logger.warn("Failed to create backup directory:", error.message);
        }
    }
    async readConfigFile() {
        try {
            // Check if config file exists
            await access(this.configPath);
            const content = await readFile(this.configPath, "utf-8");
            // Parse as JavaScript module
            const configMatch = content.match(/export default ([\s\S]+);?$/);
            if (configMatch) {
                const configJson = configMatch[1].trim();
                return JSON.parse(configJson);
            }
            throw new Error("Invalid config file format");
        }
        catch (error) {
            logger.info("Config file not found or invalid, generating default...", {
                error: error instanceof Error ? error.message : String(error),
                configPath: this.configPath,
            });
            return await this.generateDefaultConfig();
        }
    }
    async persistConfig(config) {
        const configContent = `export default ${JSON.stringify(config, null, 2)};`;
        await writeFile(this.configPath, configContent, "utf-8");
        // Clear cache after persisting
        this.config = config;
    }
    generateConfigHash(config) {
        const configString = JSON.stringify(config, Object.keys(config).sort());
        return createHash("sha256")
            .update(configString)
            .digest("hex")
            .substring(0, 8);
    }
    extractMetadataFromBackup(content) {
        const metadataMatch = content.match(/export const metadata = ([\s\S]+?);/);
        if (metadataMatch) {
            return JSON.parse(metadataMatch[1]);
        }
        throw new Error("No metadata found in backup file");
    }
    extractConfigFromBackup(content) {
        const configMatch = content.match(/export default ([\s\S]+);$/);
        if (configMatch) {
            return JSON.parse(configMatch[1]);
        }
        throw new Error("No config found in backup file");
    }
}
//# sourceMappingURL=configManager.js.map