"use strict";
// src/test_install_wizard_v2.ts
// Smoke + invariant tests for the v1.8.0 Install Wizard 2.0.
//
// Covers:
//  1. ProvidersCatalog consistency — every ProviderId has a catalog row.
//  2. OAuth policy — Anthropic OAuth is blocked, Codex/Gemini/Grok allowed.
//  3. Phase registry — all phases have unique ids and required fields.
//  4. CannedIO driver — wizard can walk through happy-path with canned answers
//     without throwing (early phases only — won't touch the filesystem).
//
// Pattern follows existing src/test_install_wizard.ts (canned-answer driver).
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 ProvidersCatalog_1 = require("./cli/install/ProvidersCatalog");
const types_1 = require("./cli/install/types");
const Phases_1 = require("./cli/install/Phases");
const WizardIO_1 = require("./cli/install/WizardIO");
const OAuthRunner_1 = require("./cli/install/OAuthRunner");
let failed = 0;
let passed = 0;
function check(name, cond, detail) {
    if (cond) {
        passed++;
        console.log(`  ✓ ${name}`);
    }
    else {
        failed++;
        console.error(`  ✗ ${name}${detail ? ` — ${detail}` : ''}`);
    }
}
async function main() {
    console.log('test_install_wizard_v2: starting');
    // ── 1. ProvidersCatalog consistency ─────────────────────────────────
    console.log('\n[1] ProvidersCatalog consistency');
    check('catalog has at least 25 entries', ProvidersCatalog_1.PROVIDERS_CATALOG.length >= 25, `actual=${ProvidersCatalog_1.PROVIDERS_CATALOG.length}`);
    // All entries have required fields
    for (const p of ProvidersCatalog_1.PROVIDERS_CATALOG) {
        check(`${p.id} has label`, p.label.length > 0);
        check(`${p.id} has tier`, !!p.tier);
        check(`${p.id} has tags`, p.tags.length > 0);
    }
    // No duplicate IDs
    const seen = new Set();
    let dupes = 0;
    for (const p of ProvidersCatalog_1.PROVIDERS_CATALOG) {
        if (seen.has(p.id))
            dupes++;
        seen.add(p.id);
    }
    check('no duplicate provider ids', dupes === 0, `dupes=${dupes}`);
    // ── 2. OAuth policy enforcement ─────────────────────────────────────
    console.log('\n[2] OAuth policy');
    const oauthList = types_1.OAUTH_ENABLED_PROVIDERS;
    check('OAUTH_ENABLED_PROVIDERS has openai-cli', oauthList.includes('openai-cli'));
    check('OAUTH_ENABLED_PROVIDERS has gemini-cli', oauthList.includes('gemini-cli'));
    check('OAUTH_ENABLED_PROVIDERS has xai (Grok)', oauthList.includes('xai'));
    check('OAUTH_ENABLED_PROVIDERS excludes anthropic', !oauthList.includes('anthropic'), 'Anthropic OAuth must be policy-blocked');
    // OAuth runner refuses Anthropic
    const antResult = await (0, OAuthRunner_1.runOAuth)('anthropic', { dryRun: true });
    check('runOAuth("anthropic") returns ok=false', antResult.ok === false, `detail=${antResult.detail}`);
    check('runOAuth("anthropic") detail mentions POLICY_BLOCK', /POLICY_BLOCK/.test(antResult.detail));
    // OAuth runner accepts Codex dry-run
    const codexResult = await (0, OAuthRunner_1.runOAuth)('openai-cli', { dryRun: true });
    check('runOAuth("openai-cli", dryRun) returns ok=true', codexResult.ok === true);
    const geminiResult = await (0, OAuthRunner_1.runOAuth)('gemini-cli', { dryRun: true });
    check('runOAuth("gemini-cli", dryRun) returns ok=true', geminiResult.ok === true);
    // ── 3. Phase registry ───────────────────────────────────────────────
    console.log('\n[3] Phase registry');
    check('ALL_PHASES has at least 20 phases', Phases_1.ALL_PHASES.length >= 20, `actual=${Phases_1.ALL_PHASES.length}`);
    const phaseIds = new Set();
    let phaseDupes = 0;
    for (const ph of Phases_1.ALL_PHASES) {
        if (phaseIds.has(ph.id))
            phaseDupes++;
        phaseIds.add(ph.id);
        check(`phase "${ph.id}" has label`, ph.label.length > 0);
        check(`phase "${ph.id}" has run fn`, typeof ph.run === 'function');
    }
    check('no duplicate phase ids', phaseDupes === 0, `dupes=${phaseDupes}`);
    // The first 3 phases (banner, existing-install, product-select) MUST be unconditional.
    const banner = Phases_1.ALL_PHASES.find(p => p.id === '00-banner');
    check('00-banner has no `when` condition', banner !== undefined && !banner.when);
    const existing = Phases_1.ALL_PHASES.find(p => p.id === '01-existing-install');
    check('01-existing-install has no `when` condition', existing !== undefined && !existing.when);
    const productSel = Phases_1.ALL_PHASES.find(p => p.id === '02-product-select');
    check('02-product-select is defined', productSel !== undefined);
    // Core / agent phases must have `when` conditions
    const coreEnter = Phases_1.ALL_PHASES.find(p => p.id === '10-core-enter');
    check('10-core-enter has `when` condition', coreEnter !== undefined && typeof coreEnter.when === 'function');
    const agentEnter = Phases_1.ALL_PHASES.find(p => p.id === '20-agent-enter');
    check('20-agent-enter has `when` condition', agentEnter !== undefined && typeof agentEnter.when === 'function');
    // ── 4. Catalog ↔ OAuth consistency ──────────────────────────────────
    console.log('\n[4] Catalog ↔ OAuth consistency');
    for (const id of types_1.OAUTH_ENABLED_PROVIDERS) {
        try {
            const p = (0, ProvidersCatalog_1.getProvider)(id);
            check(`OAuth provider "${id}" has oauthCli`, !!p.oauthCli, `oauthCli="${p.oauthCli}"`);
        }
        catch (err) {
            check(`OAuth provider "${id}" exists in catalog`, false, err instanceof Error ? err.message : String(err));
        }
    }
    // Every catalog entry with oauthCli set should appear in OAUTH_ENABLED_PROVIDERS
    for (const p of (0, ProvidersCatalog_1.oauthProviders)()) {
        check(`catalog OAuth "${p.id}" in OAUTH_ENABLED_PROVIDERS`, types_1.OAUTH_ENABLED_PROVIDERS.includes(p.id), `catalog declares oauthCli=${p.oauthCli} but type not allow-listed`);
    }
    // ── 5. CannedIO smoke (banner + existing-install only, no FS writes) ─
    // Use a clean tmp dir so phase 01 hits the "no previous install" branch
    // and doesn't prompt for abort/reinstall/repair.
    console.log('\n[5] CannedIO smoke');
    const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'openlife-test-v2-'));
    try {
        const io = new WizardIO_1.CannedIO([
            /* phase 00-banner: pause */ true,
            /* phase 01-existing-install: pause */ true,
        ]);
        const phase00 = Phases_1.ALL_PHASES.find(p => p.id === '00-banner');
        const phase01 = Phases_1.ALL_PHASES.find(p => p.id === '01-existing-install');
        const ctx = {
            root: tmpRoot,
            installMode: 'full',
            products: [],
            coreHosts: [],
            coreProviders: [],
            coreApiKeys: {},
            agentAuthDecisions: [],
            agentOAuthResults: [],
            agentApiKeys: {},
            warnings: [],
        };
        await phase00.run(ctx, io);
        await phase01.run(ctx, io);
        check('CannedIO drove first 2 phases without throwing', true);
        check('CannedIO transcript captured output', io.transcript.length > 0);
        check('ctx not aborted on clean tmpdir', !ctx.aborted);
    }
    catch (err) {
        check('CannedIO drove first 2 phases without throwing', false, err instanceof Error ? err.message : String(err));
    }
    finally {
        try {
            fs.rmSync(tmpRoot, { recursive: true, force: true });
        }
        catch { /* ignore */ }
    }
    // ── Done ────────────────────────────────────────────────────────────
    console.log('');
    console.log(`Results: ${passed} passed, ${failed} failed`);
    if (failed > 0) {
        console.error('TEST_INSTALL_WIZARD_V2_FAIL');
        process.exit(1);
    }
    console.log('✅ test_install_wizard_v2: all checks passed');
}
main().catch((err) => {
    console.error('TEST_INSTALL_WIZARD_V2_UNCAUGHT', err);
    process.exit(1);
});
