"use strict";
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 () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.InstallFlow = exports.DEFAULT_HOST = exports.VALID_HOSTS = void 0;
exports.validateHost = validateHost;
exports.detectHostFromEnv = detectHostFromEnv;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const SystemInstaller_1 = require("./SystemInstaller");
const AutonomousInstaller_1 = require("./AutonomousInstaller");
const SystemDoctor_1 = require("../orchestrator/SystemDoctor");
const ModelManager_1 = require("../orchestrator/ModelManager");
const HostInstaller_1 = require("./HostInstaller");
exports.VALID_HOSTS = ['claude-code', 'gemini-cli', 'codex'];
exports.DEFAULT_HOST = 'claude-code';
/**
 * Validates a string is a known host. Throws with a clear message listing valid hosts.
 * Use this at CLI boundary (option parsing) to reject typos early.
 */
function validateHost(value) {
    if (!value)
        return exports.DEFAULT_HOST;
    const normalized = String(value).trim().toLowerCase();
    if (!exports.VALID_HOSTS.includes(normalized)) {
        throw new Error(`INVALID_HOST: "${value}" — hosts válidos: ${exports.VALID_HOSTS.join(', ')}. Default: ${exports.DEFAULT_HOST}.`);
    }
    return normalized;
}
/**
 * Auto-detects which host CLI invoked OpenLife by inspecting env vars set by each CLI:
 * - claude-code sets CLAUDECODE or CLAUDE_PROJECT_DIR
 * - gemini-cli sets GEMINI_CONFIG_DIR
 * - codex sets CODEX_HOME
 * Returns null if no detection matches — caller falls back to DEFAULT_HOST.
 */
function detectHostFromEnv(env = process.env) {
    if (env.CLAUDECODE || env.CLAUDE_PROJECT_DIR)
        return 'claude-code';
    if (env.GEMINI_CONFIG_DIR)
        return 'gemini-cli';
    if (env.CODEX_HOME)
        return 'codex';
    return null;
}
class InstallFlow {
    root;
    systemInstaller;
    autonomousInstaller;
    doctor;
    modelManager;
    constructor(root = process.cwd(), systemInstaller = new SystemInstaller_1.SystemInstaller(root), autonomousInstaller = new AutonomousInstaller_1.AutonomousInstaller(root), doctor = new SystemDoctor_1.SystemDoctor(root), modelManager = new ModelManager_1.ModelManager()) {
        this.root = root;
        this.systemInstaller = systemInstaller;
        this.autonomousInstaller = autonomousInstaller;
        this.doctor = doctor;
        this.modelManager = modelManager;
    }
    run(options = {}) {
        const profile = options.profile || 'framework';
        // Story 3.1 — host now validated; auto-detect from env if not provided.
        const host = options.host
            ? validateHost(options.host)
            : (detectHostFromEnv() || exports.DEFAULT_HOST);
        const manifestPath = this.systemInstaller.install();
        const projectFilePath = this.systemInstaller.initProject();
        const doctorSummary = options.skipDoctor ? undefined : this.buildDoctorSummary(this.doctor.run());
        const autonomous = profile === 'autonomous' ? this.autonomousInstaller.install() : undefined;
        const modelChain = this.applyModelOrder(options.modelOrder || []);
        // Story 3.3 — host-specific file copy (templates → host CLI paths).
        // Gracefully degrade when the host installer hasn't been implemented for the
        // chosen host yet: still produce the `.openlife/` state and report, but surface
        // the skip in `hostInstall` so the user knows the host-specific copy was a no-op.
        let hostInstall;
        try {
            hostInstall = new HostInstaller_1.HostInstaller().install(host, { targetRoot: this.root });
        }
        catch (err) {
            if (err instanceof HostInstaller_1.HostNotYetSupportedError) {
                const reason = err.message;
                console.warn(`[install-flow] host install skipped: ${reason}`);
                hostInstall = { skipped: true, reason };
            }
            else {
                throw err;
            }
        }
        const nextCommands = this.buildNextCommands(profile, host);
        const report = {
            installedAt: new Date().toISOString(),
            profile,
            host,
            root: this.root,
            manifestPath,
            projectFilePath,
            doctorSummary,
            autonomous,
            modelChain,
            nextCommands,
            hostInstall
        };
        const reportPath = path.join(this.root, '.openlife', 'install-flow-report.json');
        fs.writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf-8');
        return {
            ...report,
            reportPath
        };
    }
    renderSummary(result) {
        const lines = [];
        lines.push('🚀 OpenLife Setup concluído');
        lines.push('=================================================');
        lines.push(`📁 Root: ${result.root}`);
        lines.push(`🧭 Profile: ${result.profile}`);
        lines.push(`🧠 Host: ${result.host}`);
        lines.push(`🧾 Manifest: ${result.manifestPath}`);
        lines.push(`📝 Projeto: ${result.projectFilePath}`);
        lines.push(`📦 Report: ${result.reportPath}`);
        if (result.modelChain?.length) {
            lines.push(`🧠 Model chain: ${result.modelChain.join(' -> ')}`);
        }
        if (result.doctorSummary) {
            lines.push('');
            lines.push('🩺 Doctor summary');
            lines.push(`- checks: ${result.doctorSummary.total}`);
            lines.push(`- ok: ${result.doctorSummary.ok}`);
            lines.push(`- failed: ${result.doctorSummary.failed}`);
            if (result.doctorSummary.failed > 0) {
                lines.push('- principais pendências:');
                for (const check of result.doctorSummary.failedChecks.slice(0, 5)) {
                    lines.push(`  • ${check.name}: ${check.detail}`);
                }
            }
        }
        if (result.autonomous) {
            lines.push('');
            lines.push(`🤖 Artefatos autônomos: ${result.autonomous.filesCreated.length} arquivos atualizados`);
        }
        if (result.hostInstall) {
            lines.push('');
            if ('skipped' in result.hostInstall && result.hostInstall.skipped) {
                lines.push(`🧩 Host install: skipped — ${result.hostInstall.reason}`);
            }
            else {
                const files = result.hostInstall.files;
                const created = files.filter((f) => f.action === 'created').length;
                const updated = files.filter((f) => f.action === 'updated').length;
                const unchanged = files.filter((f) => f.action === 'skipped-identical').length;
                lines.push(`🧩 Host install: ${files.length} files copied (${created} created, ${updated} updated, ${unchanged} unchanged)`);
                for (const note of result.hostInstall.notes) {
                    lines.push(`  • ${note}`);
                }
            }
        }
        lines.push('');
        lines.push('▶️ Próximos comandos (copiar e colar):');
        for (const command of result.nextCommands) {
            lines.push(`  ${command}`);
        }
        return lines;
    }
    buildDoctorSummary(checks) {
        const failedChecks = checks.filter((check) => !check.ok);
        return {
            total: checks.length,
            ok: checks.length - failedChecks.length,
            failed: failedChecks.length,
            failedChecks
        };
    }
    applyModelOrder(modelOrder) {
        const normalized = modelOrder.map(m => m.trim()).filter(Boolean);
        if (!normalized.length)
            return undefined;
        const primary = this.modelManager.parseModelString(normalized[0]);
        const fallbacks = normalized.slice(1).map(m => this.modelManager.parseModelString(m));
        const cfg = this.modelManager.getModelConfig();
        cfg.primary = primary;
        cfg.fallbacks = fallbacks;
        this.modelManager.saveConfig(cfg);
        const allowlist = Array.from(new Set(normalized.map((m) => {
            const p = m.split('/')[0].toLowerCase();
            if (p.includes('gemini'))
                return 'gemini';
            if (p.includes('openai') || p.includes('codex'))
                return 'codex';
            if (p.includes('claude') || p.includes('anthropic'))
                return 'claude';
            return '';
        }).filter(Boolean)));
        if (allowlist.length > 0) {
            const envPath = path.join(this.root, '.env');
            const current = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf-8') : '';
            const without = current
                .split('\n')
                .filter(line => !line.startsWith('OPENLIFE_ALLOWED_LLM_EXECUTORS='))
                .join('\n')
                .replace(/\n+$/, '');
            const next = `${without}\nOPENLIFE_ALLOWED_LLM_EXECUTORS=${allowlist.join(',')}\n`;
            fs.writeFileSync(envPath, next, 'utf-8');
        }
        return normalized;
    }
    buildNextCommands(profile, host) {
        // Story 3.1 — `mode set` is documented but doesn't exist; replaced with `system setup`
        // (which was the working command). Same fix shipped in commit aba599b (INSTALL.md).
        const base = [
            `openlife system setup --profile ${profile} --host ${host}`,
            'openlife system status',
            'openlife system doctor'
        ];
        if (profile === 'autonomous') {
            return [
                ...base,
                'openlife agent start',
                'openlife agent status'
            ];
        }
        return [
            ...base,
            'openlife models status'
        ];
    }
}
exports.InstallFlow = InstallFlow;
