"use strict";
/**
 * Auto-recovery for missing or corrupted configuration
 * Lazy initialization: Creates ~/.ccs/ structure on first CLI run
 * Mirrors postinstall.js behavior for package managers that skip lifecycle scripts (e.g., bun)
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const ui_1 = require("../utils/ui");
const config_manager_1 = require("../utils/config-manager");
const unified_config_types_1 = require("../config/unified-config-types");
const config_loader_facade_1 = require("../config/config-loader-facade");
/**
 * Recovery Manager Class
 */
class RecoveryManager {
    constructor() {
        this.homedir = (0, config_manager_1.getCcsHome)();
        this.ccsDir = (0, config_loader_facade_1.getCcsDir)();
        this.claudeDir = path.join(this.homedir, '.claude');
        this.sharedDir = path.join(this.ccsDir, 'shared');
        this.completionsDir = path.join(this.ccsDir, 'completions');
        this.recovered = [];
    }
    /**
     * Ensure ~/.ccs/ directory exists
     */
    ensureCcsDirectory() {
        if (!fs.existsSync(this.ccsDir)) {
            fs.mkdirSync(this.ccsDir, { recursive: true, mode: 0o755 });
            this.recovered.push(`Created ${this.ccsDir} directory`);
            return true;
        }
        return false;
    }
    /**
     * Remove a dangling symlink so recovery can recreate the directory.
     * Mirrors scripts/postinstall.js behavior for skipped lifecycle installs.
     */
    removeIfBrokenSymlink(targetPath) {
        try {
            const stats = fs.lstatSync(targetPath);
            if (!stats.isSymbolicLink()) {
                return false;
            }
            try {
                fs.statSync(targetPath);
                return false;
            }
            catch (error) {
                const code = error.code;
                if (code !== 'ENOENT' && code !== 'ENOTDIR') {
                    return false;
                }
                fs.unlinkSync(targetPath);
                this.recovered.push(`Removed broken symlink: ${targetPath}`);
                return true;
            }
        }
        catch {
            return false;
        }
    }
    inspectDirectoryPath(targetPath) {
        try {
            const stats = fs.lstatSync(targetPath);
            if (stats.isSymbolicLink()) {
                try {
                    return fs.statSync(targetPath).isDirectory()
                        ? { state: 'ready' }
                        : { state: 'invalid', reason: 'symlink target is not a directory' };
                }
                catch (error) {
                    const code = error.code;
                    return code === 'ENOENT' || code === 'ENOTDIR'
                        ? { state: 'missing' }
                        : {
                            state: 'invalid',
                            reason: `symlink target is not accessible (${code || 'unknown'})`,
                        };
                }
            }
            return stats.isDirectory()
                ? { state: 'ready' }
                : { state: 'invalid', reason: 'existing path is not a directory' };
        }
        catch (error) {
            const code = error.code;
            return code === 'ENOENT'
                ? { state: 'missing' }
                : { state: 'invalid', reason: `could not inspect path (${code || 'unknown'})` };
        }
    }
    /**
     * Ensure ~/.ccs/config.yaml exists with defaults
     * This is the primary config format (YAML unified config)
     */
    ensureConfigYaml() {
        // Skip if config.yaml already exists AND is valid
        if ((0, config_loader_facade_1.hasUnifiedConfig)()) {
            // Verify it's loadable (not corrupted)
            const loaded = (0, config_loader_facade_1.loadUnifiedConfig)();
            if (loaded !== null) {
                return false; // Config exists and is valid
            }
            // Config exists but is corrupted - will be recreated below
            this.recovered.push(`Detected corrupted ${this.ccsDir}/config.yaml`);
        }
        // Check for legacy config.json - if exists, let autoMigrate handle it
        const legacyConfigPath = path.join(this.ccsDir, 'config.json');
        if (fs.existsSync(legacyConfigPath)) {
            // Legacy config exists - autoMigrate() in ccs.ts will handle migration
            return false;
        }
        // Create fresh config.yaml with defaults
        const config = (0, unified_config_types_1.createEmptyUnifiedConfig)();
        config.version = unified_config_types_1.UNIFIED_CONFIG_VERSION;
        try {
            (0, config_loader_facade_1.saveConfig)(config);
            this.recovered.push(`Created ${this.ccsDir}/config.yaml`);
            return true;
        }
        catch (_saveErr) {
            // Fallback: create minimal config.json for backward compat
            try {
                const fallbackConfig = { profiles: {} };
                const tmpPath = `${legacyConfigPath}.tmp`;
                fs.writeFileSync(tmpPath, JSON.stringify(fallbackConfig, null, 2) + '\n', 'utf8');
                fs.renameSync(tmpPath, legacyConfigPath);
                this.recovered.push(`Created ${this.ccsDir}/config.json (fallback)`);
                return true;
            }
            catch (_fallbackErr) {
                // Both writes failed - log but don't crash
                this.recovered.push('Failed to create config file (permission issue?)');
                return false;
            }
        }
    }
    /**
     * Ensure ~/.claude/settings.json exists
     */
    ensureClaudeSettings() {
        const claudeSettingsPath = path.join(this.claudeDir, 'settings.json');
        // Create ~/.claude/ if missing
        if (!fs.existsSync(this.claudeDir)) {
            fs.mkdirSync(this.claudeDir, { recursive: true, mode: 0o755 });
            this.recovered.push(`Created ${this.claudeDir} directory`);
        }
        // Create settings.json if missing
        if (!fs.existsSync(claudeSettingsPath)) {
            const tmpPath = `${claudeSettingsPath}.tmp`;
            fs.writeFileSync(tmpPath, '{}\n', 'utf8');
            fs.renameSync(tmpPath, claudeSettingsPath);
            this.recovered.push(`Created ${claudeSettingsPath}`);
            return true;
        }
        return false;
    }
    /**
     * Ensure ~/.ccs/shared/ directory structure exists
     */
    ensureSharedDirectories() {
        let created = false;
        this.removeIfBrokenSymlink(this.sharedDir);
        const sharedState = this.inspectDirectoryPath(this.sharedDir);
        // Create shared directory
        if (sharedState.state === 'missing') {
            fs.mkdirSync(this.sharedDir, { recursive: true, mode: 0o755 });
            this.recovered.push(`Created ${this.sharedDir}`);
            created = true;
        }
        else if (sharedState.state === 'invalid') {
            this.recovered.push(`Skipped ${this.sharedDir}: ${sharedState.reason}`);
            return created;
        }
        // Create subdirectories
        const subdirs = ['commands', 'skills', 'agents', 'plugins'];
        for (const subdir of subdirs) {
            const subdirPath = path.join(this.sharedDir, subdir);
            this.removeIfBrokenSymlink(subdirPath);
            const subdirState = this.inspectDirectoryPath(subdirPath);
            if (subdirState.state === 'missing') {
                fs.mkdirSync(subdirPath, { recursive: true, mode: 0o755 });
                created = true;
                continue;
            }
            if (subdirState.state === 'invalid') {
                this.recovered.push(`Skipped ${subdirPath}: ${subdirState.reason}`);
            }
        }
        return created;
    }
    /**
     * Install shell completion files
     */
    ensureShellCompletions() {
        // Find the scripts/completion directory relative to this module
        // In dist: dist/management/recovery-manager.js → scripts/completion
        // In src: src/management/recovery-manager.ts → scripts/completion
        const possiblePaths = [
            path.join(__dirname, '..', '..', 'scripts', 'completion'), // from dist/management/
            path.join(__dirname, '..', '..', '..', 'scripts', 'completion'), // alternative
        ];
        let scriptsCompletionDir = null;
        for (const p of possiblePaths) {
            if (fs.existsSync(p)) {
                scriptsCompletionDir = p;
                break;
            }
        }
        if (!scriptsCompletionDir) {
            // Completion scripts not found - skip silently (may be installed differently)
            return false;
        }
        // Create completions directory
        if (!fs.existsSync(this.completionsDir)) {
            fs.mkdirSync(this.completionsDir, { recursive: true, mode: 0o755 });
        }
        const files = ['ccs.bash', 'ccs.zsh', 'ccs.fish', 'ccs.ps1'];
        let installed = false;
        for (const file of files) {
            const src = path.join(scriptsCompletionDir, file);
            const dest = path.join(this.completionsDir, file);
            if (fs.existsSync(src) && !fs.existsSync(dest)) {
                fs.copyFileSync(src, dest);
                installed = true;
            }
        }
        if (installed) {
            this.recovered.push(`Installed shell completions to ${this.completionsDir}`);
        }
        return installed;
    }
    /**
     * Run all recovery operations (lazy initialization)
     * Mirrors postinstall.js behavior
     *
     * NOTE: GLM/Kimi profiles are NOT auto-created.
     * Users should create them via `ccs api create --preset glm|km` or the UI.
     */
    recoverAll() {
        this.recovered = [];
        // Core directories
        this.ensureCcsDirectory();
        this.ensureSharedDirectories();
        this.ensureClaudeSettings();
        // Config files - use YAML as primary format
        this.ensureConfigYaml();
        // Shell completions
        this.ensureShellCompletions();
        return this.recovered.length > 0;
    }
    /**
     * Get recovery summary
     */
    getRecoverySummary() {
        return this.recovered;
    }
    /**
     * Show recovery hints
     */
    showRecoveryHints() {
        if (this.recovered.length === 0)
            return;
        console.log('');
        console.log((0, ui_1.info)('Auto-recovery completed:'));
        this.recovered.forEach((msg) => console.log(`    - ${msg}`));
        // Show login hint if created Claude settings
        if (this.recovered.some((msg) => msg.includes('settings.json') && msg.includes('.claude'))) {
            console.log('');
            console.log((0, ui_1.info)('Next step: Login to Claude CLI'));
            console.log('    Run: claude /login');
        }
        console.log('');
    }
}
exports.default = RecoveryManager;
//# sourceMappingURL=recovery-manager.js.map