"use strict";
// Story 3.5 — Regression test for the interactive install wizard.
// Uses CannedAnswerProvider so no real stdin/tty is required.
//
// Question order in wizard.run() (when no pre-existing install):
//   1) profile          (choice: 0=framework, 1=autonomous, 2=both)
//   2) host             (choice: 0=claude-code, 1=gemini-cli, 2=codex)
//   3) wantsApiKeys     (yesNo)
//   3a-d) [if Y] OPENAI / ANTHROPIC / GEMINI / OPENROUTER pastes (text)
//   4) wantsOAuth       (yesNo)
//   5) model order      (text: blank or comma list)
//   6) telegram?        (yesNo, autonomous only)
//   7) skip doctor?     (yesNo)
//   8) confirm preview  (yesNo)
//
// When pre-existing install detected, an extra choice prompt fires FIRST:
//   0) abort  1) reinstall  2) repair
// Selecting abort short-circuits the rest of the flow.
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 });
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const InstallWizard_1 = require("./cli/InstallWizard");
function assert(cond, msg) {
    if (!cond) {
        console.error(`❌ ASSERT FAILED: ${msg}`);
        process.exit(1);
    }
}
function tempRoot() {
    return fs.mkdtempSync(path.join(os.tmpdir(), 'openlife-init-wizard-'));
}
function cleanup(root) {
    try {
        fs.rmSync(root, { recursive: true, force: true });
    }
    catch {
        // best-effort
    }
}
function writeExistingInstall(root) {
    const dir = path.join(root, '.openlife');
    fs.mkdirSync(dir, { recursive: true });
    fs.writeFileSync(path.join(dir, 'install-manifest.json'), JSON.stringify({ installedAt: new Date().toISOString(), version: 'test' }, null, 2), 'utf-8');
}
async function scenario1HappyPathFrameworkClaudeCode() {
    const root = tempRoot();
    try {
        // profile=framework(0), host=claude-code(0), apiKeys=N, oauth=N, models='', skipDoctor=false, confirm=true
        const provider = new InstallWizard_1.CannedAnswerProvider([0, 0, false, false, '', false, true]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === true, 'scenario1: expected ok=true');
        if (!result.ok)
            return;
        assert(result.options.profile === 'framework', 'scenario1: profile should be framework');
        assert(result.options.host === 'claude-code', 'scenario1: host should be claude-code');
        assert(result.options.skipDoctor === false, 'scenario1: skipDoctor should be false');
        assert(result.options.modelOrder === undefined, 'scenario1: modelOrder should be undefined when blank');
        assert(result.preExistingAction === undefined, 'scenario1: no pre-existing action expected');
        // SKIPPED_API_KEYS warning is expected when wantsApiKeys=false
        assert(Array.isArray(result.warnings) && result.warnings.some((w) => w.includes('SKIPPED_API_KEYS')), 'scenario1: should warn SKIPPED_API_KEYS when api-key prompt skipped');
        console.log('✅ scenario 1: happy path framework + claude-code');
    }
    finally {
        cleanup(root);
    }
}
async function scenario2HappyPathAutonomousClaudeCode() {
    const root = tempRoot();
    try {
        // profile=autonomous(1), host=claude-code(0), apiKeys=N, oauth=N, models='', telegram=true, skipDoctor=false, confirm=true
        const provider = new InstallWizard_1.CannedAnswerProvider([1, 0, false, false, '', true, false, true]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === true, 'scenario2: expected ok=true');
        if (!result.ok)
            return;
        assert(result.options.profile === 'autonomous', 'scenario2: profile should be autonomous');
        assert(result.options.host === 'claude-code', 'scenario2: host should be claude-code');
        // SKIPPED_API_KEYS warning is expected when wantsApiKeys=false
        assert(Array.isArray(result.warnings) && result.warnings.some((w) => w.includes('SKIPPED_API_KEYS')), 'scenario2: should warn SKIPPED_API_KEYS when api-key prompt skipped');
        console.log('✅ scenario 2: happy path autonomous + claude-code');
    }
    finally {
        cleanup(root);
    }
}
async function scenario3UserAbortsOnConfirm() {
    const root = tempRoot();
    try {
        // framework, claude-code, apiKeys=N, oauth=N, blank models, skipDoctor=false, confirm=false (abort)
        const provider = new InstallWizard_1.CannedAnswerProvider([0, 0, false, false, '', false, false]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === false, 'scenario3: expected ok=false');
        if (result.ok)
            return;
        assert(result.reason === 'user_aborted', 'scenario3: reason should be user_aborted');
        assert(result.detail === 'preview_not_confirmed', 'scenario3: detail should be preview_not_confirmed');
        console.log('✅ scenario 3: user aborts on confirm-preview');
    }
    finally {
        cleanup(root);
    }
}
async function scenario4PreExistingAbort() {
    const root = tempRoot();
    try {
        writeExistingInstall(root);
        // pre-existing prompt: 0=abort. No further questions should fire.
        const provider = new InstallWizard_1.CannedAnswerProvider([0]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === false, 'scenario4: expected ok=false');
        if (result.ok)
            return;
        assert(result.reason === 'user_aborted', 'scenario4: reason should be user_aborted');
        assert(result.detail === 'pre_existing_install_abort', 'scenario4: detail should be pre_existing_install_abort');
        assert(provider.remaining() === 0, 'scenario4: queue should be empty (no further questions asked)');
        console.log('✅ scenario 4: pre-existing install + abort short-circuits');
    }
    finally {
        cleanup(root);
    }
}
async function scenario5PreExistingRepair() {
    const root = tempRoot();
    try {
        writeExistingInstall(root);
        // 2=repair, then full flow: framework, claude-code, apiKeys=N, oauth=N, '', skipDoctor=false, confirm=true
        const provider = new InstallWizard_1.CannedAnswerProvider([2, 0, 0, false, false, '', false, true]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === true, 'scenario5: expected ok=true');
        if (!result.ok)
            return;
        assert(result.preExistingAction === 'repair', 'scenario5: preExistingAction should be repair');
        assert(result.options.profile === 'framework', 'scenario5: profile should be framework');
        console.log('✅ scenario 5: pre-existing install + repair');
    }
    finally {
        cleanup(root);
    }
}
async function scenario6PreExistingReinstall() {
    const root = tempRoot();
    try {
        writeExistingInstall(root);
        // 1=reinstall, framework, claude-code, apiKeys=N, oauth=N, '', skipDoctor=false, confirm=true
        const provider = new InstallWizard_1.CannedAnswerProvider([1, 0, 0, false, false, '', false, true]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === true, 'scenario6: expected ok=true');
        if (!result.ok)
            return;
        assert(result.preExistingAction === 'reinstall', 'scenario6: preExistingAction should be reinstall');
        console.log('✅ scenario 6: pre-existing install + reinstall');
    }
    finally {
        cleanup(root);
    }
}
async function scenario7UnsupportedHostGeminiCli() {
    const root = tempRoot();
    try {
        // framework, host=1 (gemini-cli, not yet supported), apiKeys=N, oauth=N, blank models, skipDoctor=false, confirm=true
        const provider = new InstallWizard_1.CannedAnswerProvider([0, 1, false, false, '', false, true]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === true, 'scenario7: expected ok=true even with unsupported host');
        if (!result.ok)
            return;
        assert(result.options.host === 'gemini-cli', 'scenario7: host should be gemini-cli');
        assert(Array.isArray(result.warnings), 'scenario7: should have warnings array');
        assert(result.warnings.some((w) => w.includes('HOST_NOT_YET_SUPPORTED')), 'scenario7: should warn HOST_NOT_YET_SUPPORTED');
        console.log('✅ scenario 7: unsupported host (gemini-cli) accepted with warning');
    }
    finally {
        cleanup(root);
    }
}
async function scenario8CustomModelChain() {
    const root = tempRoot();
    try {
        const models = 'gemini-api/gemini-3.1-pro-preview,openai-api/gpt-5.4-mini';
        // framework, claude-code, apiKeys=N, oauth=N, models=custom, skipDoctor=false, confirm=true
        const provider = new InstallWizard_1.CannedAnswerProvider([0, 0, false, false, models, false, true]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === true, 'scenario8: expected ok=true');
        if (!result.ok)
            return;
        assert(Array.isArray(result.options.modelOrder), 'scenario8: modelOrder should be array');
        assert(result.options.modelOrder.length === 2, 'scenario8: modelOrder should have 2 entries');
        assert(result.options.modelOrder[0] === 'gemini-api/gemini-3.1-pro-preview', 'scenario8: first model should be gemini-3.1-pro-preview');
        assert(result.options.modelOrder[1] === 'openai-api/gpt-5.4-mini', 'scenario8: second model should be gpt-5.4-mini');
        console.log('✅ scenario 8: custom model chain parsed correctly');
    }
    finally {
        cleanup(root);
    }
}
async function scenario9OutOfAnswersThrows() {
    const root = tempRoot();
    try {
        // Provide too few answers: stop after profile.
        const provider = new InstallWizard_1.CannedAnswerProvider([0]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        let threw = false;
        let detail = '';
        try {
            await wizard.run();
        }
        catch (err) {
            threw = true;
            detail = err instanceof Error ? err.message : String(err);
        }
        assert(threw, 'scenario9: wizard should throw when canned queue is exhausted');
        assert(detail.includes('WIZARD_TEST_OUT_OF_ANSWERS'), `scenario9: error should mention WIZARD_TEST_OUT_OF_ANSWERS; got: ${detail}`);
        console.log('✅ scenario 9: CannedAnswerProvider throws WIZARD_TEST_OUT_OF_ANSWERS on dry queue');
    }
    finally {
        cleanup(root);
    }
}
async function scenario10WithApiKeysPersists() {
    const root = tempRoot();
    try {
        // framework, claude-code, apiKeys=Y, paste 4 keys (openai+anthropic, skip gemini+openrouter),
        // oauth=N, blank models, skipDoctor=false, confirm=true
        const provider = new InstallWizard_1.CannedAnswerProvider([
            0, 0,
            true, // wantsApiKeys
            'openai-test-key', // openai paste (non-secret test fixture)
            'anthropic-test-key', // anthropic paste (non-secret test fixture)
            '', // gemini skip
            '', // openrouter skip
            false, // wantsOAuth
            '', // models
            false, // skipDoctor
            true, // confirm
        ]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === true, 'scenario10: expected ok=true');
        if (!result.ok)
            return;
        // .env should contain the pasted keys
        const envPath = path.join(root, '.env');
        assert(fs.existsSync(envPath), 'scenario10: .env should exist after wizard');
        const envContent = fs.readFileSync(envPath, 'utf-8');
        assert(envContent.includes('OPENAI_API_KEY=openai-test-key'), 'scenario10: .env should have OPENAI_API_KEY');
        assert(envContent.includes('ANTHROPIC_API_KEY=anthropic-test-key'), 'scenario10: .env should have ANTHROPIC_API_KEY');
        assert(!envContent.includes('GEMINI_API_KEY='), 'scenario10: .env should NOT have GEMINI_API_KEY (skipped)');
        // SKIPPED_API_KEYS warning should NOT fire when at least one key was provided
        if (result.warnings) {
            assert(!result.warnings.some((w) => w.includes('SKIPPED_API_KEYS')), 'scenario10: should NOT warn SKIPPED_API_KEYS when keys were provided');
        }
        console.log('✅ scenario 10: API keys collected and persisted to .env');
    }
    finally {
        cleanup(root);
    }
}
async function scenario11AbortDoesNotPersistApiKeys() {
    const root = tempRoot();
    try {
        const provider = new InstallWizard_1.CannedAnswerProvider([
            0, 0,
            true,
            'openai-abort-test-key',
            '',
            '',
            '',
            false,
            '',
            false,
            false,
        ]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === false, 'scenario11: expected ok=false');
        assert(!fs.existsSync(path.join(root, '.env')), 'scenario11: aborted wizard must not write .env');
        console.log('✅ scenario 11: abort after API-key collection does not persist .env');
    }
    finally {
        cleanup(root);
    }
}
async function scenario12ProfileBothMapsToAutonomous() {
    const root = tempRoot();
    try {
        // profile=both(2), claude-code, apiKeys=N, oauth=N, models='', telegram=true (autonomous path),
        // skipDoctor=false, confirm=true
        const provider = new InstallWizard_1.CannedAnswerProvider([2, 0, false, false, '', true, false, true]);
        const wizard = new InstallWizard_1.InstallWizard(root, provider);
        const result = await wizard.run();
        assert(result.ok === true, 'scenario11: expected ok=true');
        if (!result.ok)
            return;
        assert(result.options.profile === 'autonomous', 'scenario11: profile=both should map internally to autonomous');
        assert(Array.isArray(result.warnings) && result.warnings.some((w) => w.includes('INSTALLING_BOTH')), 'scenario11: should emit INSTALLING_BOTH warning so caller knows both layers were intended');
        console.log('✅ scenario 11: profile=both maps to autonomous with INSTALLING_BOTH warning');
    }
    finally {
        cleanup(root);
    }
}
async function main() {
    console.log('🧪 test_install_wizard — Story 3.5 regression suite');
    await scenario1HappyPathFrameworkClaudeCode();
    await scenario2HappyPathAutonomousClaudeCode();
    await scenario3UserAbortsOnConfirm();
    await scenario4PreExistingAbort();
    await scenario5PreExistingRepair();
    await scenario6PreExistingReinstall();
    await scenario7UnsupportedHostGeminiCli();
    await scenario8CustomModelChain();
    await scenario9OutOfAnswersThrows();
    await scenario10WithApiKeysPersists();
    await scenario11AbortDoesNotPersistApiKeys();
    await scenario12ProfileBothMapsToAutonomous();
    console.log('');
    console.log('TEST_INSTALL_WIZARD_OK');
}
main().catch((err) => {
    console.error('❌ test_install_wizard failed:', err);
    process.exit(1);
});
