"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.setupPromptTestHooks = void 0;
exports.runSetup = runSetup;
exports.createSetupCommand = createSetupCommand;
const core_1 = require("@clack/core");
const p = __importStar(require("@clack/prompts"));
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const kleur_1 = require("kleur");
const env_loader_1 = require("../utils/env-loader");
const project_files_1 = require("../utils/project-files");
const docker_compose_1 = require("../services/docker-compose");
const cert_manager_1 = require("../services/cert-manager");
const domain_checker_1 = require("../services/domain-checker");
const port_checker_1 = require("../services/port-checker");
const path_helpers_1 = require("../utils/path-helpers");
const command_1 = require("../utils/command");
const logo_1 = require("../utils/logo");
const tool_state_1 = require("../utils/tool-state");
const i18n_1 = require("../i18n");
const STEP_BACK = Symbol('runestone:step-back');
const BACK_KEY = '\x1b';
let activeT = (0, i18n_1.createTranslator)((0, i18n_1.resolveLocale)());
function setActiveLocale(locale) {
    activeT = (0, i18n_1.createTranslator)(locale);
}
function cancelIfNeeded(value) {
    if (p.isCancel(value)) {
        p.cancel(activeT('setup.cancelled'));
        process.exit(0);
    }
    return value;
}
function isStepBack(value) {
    return value === STEP_BACK;
}
function expandHome(value) {
    if (value === '~') {
        return os.homedir();
    }
    if (value.startsWith(`~${path.sep}`) || value.startsWith('~/') || value.startsWith('~\\')) {
        return path.join(os.homedir(), value.slice(2));
    }
    return value;
}
function setupEnvPath(projectDir, envPath) {
    return envPath ? path.resolve(expandHome(envPath)) : path.join(projectDir, '.env');
}
function childPrompt(message) {
    return `── ${message}`;
}
function promptSymbol(state) {
    switch (state) {
        case 'submit':
            return (0, kleur_1.green)('◇');
        case 'cancel':
            return (0, kleur_1.red)('■');
        case 'error':
            return (0, kleur_1.yellow)('▲');
        default:
            return (0, kleur_1.cyan)('◆');
    }
}
function optionLabel(option, state) {
    const label = option.label ?? String(option.value);
    if (state === 'active') {
        return `${(0, kleur_1.green)('●')} ${label}${option.hint ? ` ${(0, kleur_1.dim)(`(${option.hint})`)}` : ''}`;
    }
    if (state === 'selected') {
        return (0, kleur_1.dim)(label);
    }
    if (state === 'cancelled') {
        return (0, kleur_1.strikethrough)((0, kleur_1.dim)(label));
    }
    return `${(0, kleur_1.dim)('○')} ${(0, kleur_1.dim)(label)}`;
}
function enableBackHotkey(prompt, canBack) {
    if (!canBack) {
        return;
    }
    const promptInternal = prompt;
    const originalOnKeypress = promptInternal.onKeypress?.bind(prompt);
    promptInternal.onKeypress = (input, key) => {
        if (input === BACK_KEY || key?.name === 'escape' || key?.sequence === BACK_KEY) {
            promptInternal.value = STEP_BACK;
            promptInternal.state = 'submit';
            promptInternal.emit?.('finalize');
            promptInternal.render?.();
            promptInternal.close?.();
            return;
        }
        originalOnKeypress?.(input, key);
    };
}
exports.setupPromptTestHooks = {
    enableBackHotkey,
    STEP_BACK
};
function promptDescription(description) {
    if (!description) {
        return '';
    }
    const lines = Array.isArray(description) ? description : [description];
    return `${lines.map((line) => `${(0, kleur_1.gray)('│')}  ${(0, kleur_1.dim)(`- ${line}`)}`).join('\n')}\n`;
}
function promptHotkeys(canBack) {
    const hotkeys = [canBack ? activeT('setup.hotkey.back') : undefined, activeT('setup.hotkey.next'), activeT('setup.hotkey.cancel')];
    return hotkeys.filter(Boolean).join((0, kleur_1.dim)(' / '));
}
function promptHeader(state, message, frame) {
    return `${(0, kleur_1.gray)('│')}\n${promptSymbol(state)}  ${message}\n${promptDescription(frame?.description)}`;
}
function promptFooter(canBack, color = kleur_1.cyan) {
    return `${color('│')}\n${color('└')}  ${(0, kleur_1.dim)(promptHotkeys(canBack))}\n`;
}
function settingsChanged(existing, next) {
    if (!existing?.ENV_FILE_EXISTS) {
        return false;
    }
    return Object.keys(next).some((key) => String(existing[key]) !== String(next[key]));
}
function resetConfiguredValues(draft) {
    draft.dockerDomain = undefined;
    draft.projectPrefix = undefined;
    draft.webEntrypointName = undefined;
    draft.webEntrypointPort = undefined;
    draft.webSecureEntrypointName = undefined;
    draft.webSecureEntrypointPort = undefined;
    draft.smtpPort = undefined;
    draft.installMkcert = undefined;
}
function setupConfigInput(draft) {
    return {
        HOST_DOMAIN: draft.dockerDomain,
        PREFIX: draft.projectPrefix,
        HTTPS_PORT: draft.webSecureEntrypointPort,
        HTTP_PORT: draft.webEntrypointPort,
        SMTP_PORT: draft.smtpPort,
        WEB_ENTRYPOINT_PORT: draft.webEntrypointPort,
        WEB_SECURE_ENTRYPOINT_PORT: draft.webSecureEntrypointPort,
        RUNESTONE_IMAGE: 'cymondez/runestone',
        RUNESTONE_TAG: '5.2',
        MKCERT_INSTALLED: String(Boolean(draft.installMkcert)),
        WEB_ENTRYPOINT_NAME: draft.webEntrypointName,
        WEB_SECURE_ENTRYPOINT_NAME: draft.webSecureEntrypointName
    };
}
function reviewLines(draft) {
    return [
        `${activeT('setup.runestonePath.title')}: ${draft.projectDir}`,
        `${activeT('setup.language.title')}: ${draft.selectedLocale}`,
        `${activeT('setup.dockerDomain.title')}: ${draft.dockerDomain}`,
        `${activeT('setup.projectPrefix.title')}: ${draft.projectPrefix}`,
        `${activeT('setup.httpName.prompt')}: ${draft.webEntrypointName}`,
        `${activeT('setup.httpPort.prompt')}: ${draft.webEntrypointPort}`,
        `${activeT('setup.httpsName.prompt')}: ${draft.webSecureEntrypointName}`,
        `${activeT('setup.httpsPort.prompt')}: ${draft.webSecureEntrypointPort}`,
        `${activeT('setup.mailpit.prompt')}: ${draft.smtpPort}`,
        `${activeT('setup.localCa.prompt')} ${draft.installMkcert ? activeT('common.yes') : activeT('common.no')}`
    ];
}
function validatePort(value) {
    const trimmed = value.trim();
    if (!/^\d+$/.test(trimmed)) {
        return activeT('setup.port.number');
    }
    const port = Number(trimmed);
    if (port < 1 || port > 65535) {
        return activeT('setup.port.range');
    }
    return undefined;
}
async function promptText(message, initialValue, validate, canBack = false, frame) {
    const prompt = new core_1.TextPrompt({
        initialValue,
        validate,
        render() {
            const header = promptHeader(this.state, message, frame);
            const value = this.value ? this.valueWithCursor : (0, kleur_1.inverse)((0, kleur_1.hidden)('_'));
            switch (this.state) {
                case 'error':
                    return `${header}${(0, kleur_1.yellow)('│')}  ${value}\n${(0, kleur_1.yellow)('│')}  ${(0, kleur_1.yellow)(this.error)}\n${promptFooter(canBack, kleur_1.yellow)}`;
                case 'submit':
                    if (isStepBack(this.value)) {
                        return `${header}${(0, kleur_1.gray)('│')}  ${(0, kleur_1.dim)(activeT('setup.backSubmitted'))}`;
                    }
                    return `${header}${(0, kleur_1.gray)('│')}  ${(0, kleur_1.dim)(this.value || initialValue)}`;
                case 'cancel':
                    return `${header}${(0, kleur_1.gray)('│')}  ${(0, kleur_1.strikethrough)((0, kleur_1.dim)(this.value ?? ''))}`;
                default:
                    return `${header}${(0, kleur_1.cyan)('│')}  ${value}\n${promptFooter(canBack)}`;
            }
        }
    });
    enableBackHotkey(prompt, canBack);
    const result = cancelIfNeeded(await prompt.prompt());
    return isStepBack(result) ? STEP_BACK : result.trim();
}
async function promptConfirm(options) {
    const active = options.active ?? activeT('common.yes');
    const inactive = options.inactive ?? activeT('common.no');
    const canBack = options.canBack ?? false;
    const prompt = new core_1.ConfirmPrompt({
        active,
        inactive,
        initialValue: options.initialValue,
        render() {
            const header = promptHeader(this.state, options.message, options.frame);
            const value = this.value ? active : inactive;
            switch (this.state) {
                case 'submit':
                    if (isStepBack(this.value)) {
                        return `${header}${(0, kleur_1.gray)('│')}  ${(0, kleur_1.dim)(activeT('setup.backSubmitted'))}`;
                    }
                    return `${header}${(0, kleur_1.gray)('│')}  ${(0, kleur_1.dim)(value)}`;
                case 'cancel':
                    return `${header}${(0, kleur_1.gray)('│')}  ${(0, kleur_1.strikethrough)((0, kleur_1.dim)(value))}\n${(0, kleur_1.gray)('│')}`;
                default:
                    return `${header}${(0, kleur_1.cyan)('│')}  ${this.value ? `${(0, kleur_1.green)('●')} ${active}` : `${(0, kleur_1.dim)('○')} ${(0, kleur_1.dim)(active)}`} ${(0, kleur_1.dim)('/')} ${this.value ? `${(0, kleur_1.dim)('○')} ${(0, kleur_1.dim)(inactive)}` : `${(0, kleur_1.green)('●')} ${inactive}`}\n${promptFooter(canBack)}`;
            }
        }
    });
    enableBackHotkey(prompt, canBack);
    return cancelIfNeeded((await prompt.prompt()));
}
async function promptSelect(options) {
    const canBack = options.canBack ?? false;
    const prompt = new core_1.SelectPrompt({
        options: options.options,
        initialValue: options.initialValue,
        render() {
            const header = promptHeader(this.state, options.message, options.frame);
            switch (this.state) {
                case 'submit':
                    if (isStepBack(this.value)) {
                        return `${header}${(0, kleur_1.gray)('│')}  ${(0, kleur_1.dim)(activeT('setup.backSubmitted'))}`;
                    }
                    return `${header}${(0, kleur_1.gray)('│')}  ${optionLabel(this.options[this.cursor], 'selected')}`;
                case 'cancel':
                    return `${header}${(0, kleur_1.gray)('│')}  ${optionLabel(this.options[this.cursor], 'cancelled')}\n${(0, kleur_1.gray)('│')}`;
                default:
                    return `${header}${(0, kleur_1.cyan)('│')}  ${this.options
                        .map((option, index) => optionLabel(option, index === this.cursor ? 'active' : 'inactive'))
                        .join(`\n${(0, kleur_1.cyan)('│')}  `)}\n${promptFooter(canBack)}`;
            }
        }
    });
    enableBackHotkey(prompt, canBack);
    return cancelIfNeeded((await prompt.prompt()));
}
async function promptReview(draft) {
    const result = await promptSelect({
        message: activeT('setup.review.prompt'),
        options: [
            { value: 'apply', label: activeT('setup.review.apply') },
            { value: 'back', label: activeT('setup.review.back') },
            { value: 'cancel', label: activeT('setup.review.cancel') }
        ],
        initialValue: 'apply',
        canBack: true,
        frame: {
            description: reviewLines(draft)
        }
    });
    return isStepBack(result) ? 'back' : result;
}
async function promptPort(options) {
    while (true) {
        const value = await promptText(options.message, options.initialValue, validatePort, options.canBack, options.frame);
        if (isStepBack(value)) {
            return STEP_BACK;
        }
        if (value === options.allowOccupiedValue) {
            return value;
        }
        const available = await (0, port_checker_1.isPortAvailable)(Number(value));
        if (available) {
            return value;
        }
        p.log.warn(activeT('setup.port.inUse', { port: value }));
    }
}
function logDomainCheckResult(result) {
    p.log.info([
        activeT('setup.domainCheck.localAddresses', { domain: result.domain }),
        ...result.localAddresses.map((address) => `  - ${address}`),
        activeT('setup.domainCheck.externalIpv6', { value: result.hasExternalIpv6 ? 'yes' : 'no' })
    ].join('\n'));
    for (const host of result.checkedHosts) {
        const lines = [
            activeT('setup.domainCheck.resolvedTo', { host: host.host }),
            ...(host.resolved.length > 0
                ? host.resolved.map((record) => `  - ${record.address}`)
                : [`  - ${activeT('setup.domainCheck.noRecords')}`])
        ];
        p.log.info(lines.join('\n'));
        for (const warning of host.warnings) {
            p.log.warn(warning);
        }
        for (const error of host.errors) {
            p.log.error(error);
        }
    }
}
async function maybeCheckDockerDomain(domain, canBack) {
    if (domain === env_loader_1.DEFAULT_ENV.HOST_DOMAIN) {
        return 'next';
    }
    const shouldCheck = await promptConfirm({
        message: activeT('setup.domainCheck.prompt'),
        active: activeT('common.yes'),
        inactive: activeT('common.no'),
        initialValue: true,
        canBack,
        frame: {
            description: [
                activeT('setup.domainCheck.description1', { domain }),
                activeT('setup.domainCheck.description2', { domain }),
                activeT('setup.domainCheck.description3')
            ]
        }
    });
    if (isStepBack(shouldCheck)) {
        return 'back';
    }
    if (!shouldCheck) {
        p.log.warn(activeT('setup.domainCheck.skipped'));
        return 'next';
    }
    const spinner = p.spinner();
    spinner.start(activeT('setup.domainCheck.spinner'));
    const result = await (0, domain_checker_1.checkDomainResolvesToThisMachine)(domain);
    spinner.stop(activeT('setup.domainCheck.spinnerDone', { status: result.status }));
    logDomainCheckResult(result);
    if (result.status === 'pass') {
        p.log.success(activeT('setup.domainCheck.success'));
        return 'next';
    }
    const continueAnyway = await promptConfirm({
        message: result.status === 'warn'
            ? activeT('setup.domainCheck.warnContinue')
            : activeT('setup.domainCheck.failContinue'),
        active: activeT('common.yes'),
        inactive: activeT('common.no'),
        initialValue: result.status === 'warn',
        canBack
    });
    if (isStepBack(continueAnyway)) {
        return 'back';
    }
    if (!continueAnyway) {
        p.cancel(activeT('setup.domainCheck.cancelled'));
        process.exit(1);
    }
    return 'next';
}
async function createDefaultCertificates(projectDir, domain) {
    const certsDir = path.join(projectDir, 'certs');
    path_helpers_1.pathHelpers.ensureDir(certsDir);
    await (0, cert_manager_1.ensureWildcardCertificate)(projectDir, domain, { installLocalCa: true });
    await (0, cert_manager_1.ensureWildcardCertificate)(projectDir, 'traefik.me', { installLocalCa: true });
    const aliasResult = (0, cert_manager_1.ensureRootCaAliases)(certsDir);
    for (const warning of aliasResult.warnings) {
        p.log.warn(warning);
    }
}
async function runSetup(options = {}) {
    p.intro((0, logo_1.loadRunestoneLogo)());
    const initialProjectDir = path_helpers_1.pathHelpers.resolveProjectDir(options.project);
    const initialEnvPath = setupEnvPath(initialProjectDir, options.envPath);
    const initialExistingConfig = fs.existsSync(initialEnvPath) ? env_loader_1.envLoader.load(initialEnvPath, initialProjectDir) : undefined;
    const draft = {
        projectDir: initialProjectDir,
        envPath: initialEnvPath,
        existingConfig: initialExistingConfig,
        selectedLocale: (0, i18n_1.initialSetupLocale)(tool_state_1.toolState.readLocale())
    };
    setActiveLocale(draft.selectedLocale);
    let announcedEnvPath;
    const announceExistingSettings = () => {
        if (draft.existingConfig?.ENV_FILE_EXISTS && announcedEnvPath !== draft.envPath) {
            p.log.info(activeT('setup.existingSettings', { envPath: draft.envPath }));
            announcedEnvPath = draft.envPath;
        }
    };
    const steps = [
        async (canBack) => {
            const selectedLocale = await promptSelect({
                message: activeT('setup.language.prompt'),
                options: (0, i18n_1.languageChoices)(),
                initialValue: draft.selectedLocale,
                canBack,
                frame: { description: activeT('setup.language.description') }
            });
            if (isStepBack(selectedLocale)) {
                return 'back';
            }
            draft.selectedLocale = selectedLocale;
            setActiveLocale(draft.selectedLocale);
            return 'next';
        }
    ];
    if (!options.project && !options.envPath && !initialExistingConfig?.ENV_FILE_EXISTS) {
        steps.push(async (canBack) => {
            const selectedPath = await promptText(activeT('setup.runestonePath.title'), draft.projectDir, (value) => (!value.trim() ? activeT('setup.runestonePath.required') : undefined), canBack, { description: activeT('setup.runestonePath.description') });
            if (isStepBack(selectedPath)) {
                return 'back';
            }
            const nextProjectDir = path.resolve(expandHome(selectedPath));
            if (nextProjectDir !== draft.projectDir) {
                resetConfiguredValues(draft);
                announcedEnvPath = undefined;
            }
            draft.projectDir = nextProjectDir;
            draft.envPath = setupEnvPath(draft.projectDir, options.envPath);
            draft.existingConfig = fs.existsSync(draft.envPath) ? env_loader_1.envLoader.load(draft.envPath, draft.projectDir) : undefined;
            return 'next';
        });
    }
    steps.push(async (canBack) => {
        announceExistingSettings();
        while (true) {
            const dockerDomain = await promptText(activeT('setup.dockerDomain.title'), draft.dockerDomain ?? draft.existingConfig?.HOST_DOMAIN ?? env_loader_1.DEFAULT_ENV.HOST_DOMAIN, (value) => (!value.trim() ? activeT('setup.dockerDomain.required') : undefined), canBack, { description: activeT('setup.dockerDomain.description') });
            if (isStepBack(dockerDomain)) {
                return 'back';
            }
            draft.dockerDomain = dockerDomain;
            const domainCheckResult = await maybeCheckDockerDomain(draft.dockerDomain, true);
            if (domainCheckResult === 'back') {
                continue;
            }
            return 'next';
        }
    }, async (canBack) => {
        const projectPrefix = await promptText(activeT('setup.projectPrefix.title'), draft.projectPrefix ?? draft.existingConfig?.PREFIX ?? env_loader_1.DEFAULT_ENV.PREFIX, (value) => (!value.trim() ? activeT('setup.projectPrefix.required') : undefined), canBack, { description: activeT('setup.projectPrefix.description') });
        if (isStepBack(projectPrefix)) {
            return 'back';
        }
        draft.projectPrefix = projectPrefix;
        return 'next';
    }, async (canBack) => {
        const webEntrypointName = await promptText(childPrompt(activeT('setup.httpName.prompt')), draft.webEntrypointName ?? draft.existingConfig?.WEB_ENTRYPOINT_NAME ?? env_loader_1.DEFAULT_ENV.WEB_ENTRYPOINT_NAME, (value) => (!value.trim() ? activeT('setup.httpName.required') : undefined), canBack, {
            description: [
                activeT('setup.httpGroup.title'),
                activeT('setup.httpGroup.description1'),
                activeT('setup.httpGroup.description2')
            ]
        });
        if (isStepBack(webEntrypointName)) {
            return 'back';
        }
        draft.webEntrypointName = webEntrypointName;
        return 'next';
    }, async (canBack) => {
        const webEntrypointPort = await promptPort({
            initialValue: draft.webEntrypointPort ?? draft.existingConfig?.WEB_ENTRYPOINT_PORT ?? env_loader_1.DEFAULT_ENV.WEB_ENTRYPOINT_PORT,
            allowOccupiedValue: draft.existingConfig?.WEB_ENTRYPOINT_PORT,
            message: childPrompt(activeT('setup.httpPort.prompt')),
            canBack,
            frame: {
                description: [
                    activeT('setup.httpGroup.title'),
                    activeT('setup.httpGroup.description1'),
                    activeT('setup.httpGroup.description2')
                ]
            }
        });
        if (isStepBack(webEntrypointPort)) {
            return 'back';
        }
        draft.webEntrypointPort = webEntrypointPort;
        return 'next';
    }, async (canBack) => {
        const webSecureEntrypointName = await promptText(childPrompt(activeT('setup.httpsName.prompt')), draft.webSecureEntrypointName ?? draft.existingConfig?.WEB_SECURE_ENTRYPOINT_NAME ?? env_loader_1.DEFAULT_ENV.WEB_SECURE_ENTRYPOINT_NAME, (value) => (!value.trim() ? activeT('setup.httpsName.required') : undefined), canBack, {
            description: [
                activeT('setup.httpsGroup.title'),
                activeT('setup.httpsGroup.description1'),
                activeT('setup.httpsGroup.description2')
            ]
        });
        if (isStepBack(webSecureEntrypointName)) {
            return 'back';
        }
        draft.webSecureEntrypointName = webSecureEntrypointName;
        return 'next';
    }, async (canBack) => {
        const webSecureEntrypointPort = await promptPort({
            initialValue: draft.webSecureEntrypointPort ??
                draft.existingConfig?.WEB_SECURE_ENTRYPOINT_PORT ??
                env_loader_1.DEFAULT_ENV.WEB_SECURE_ENTRYPOINT_PORT,
            allowOccupiedValue: draft.existingConfig?.WEB_SECURE_ENTRYPOINT_PORT,
            message: childPrompt(activeT('setup.httpsPort.prompt')),
            canBack,
            frame: {
                description: [
                    activeT('setup.httpsGroup.title'),
                    activeT('setup.httpsGroup.description1'),
                    activeT('setup.httpsGroup.description2')
                ]
            }
        });
        if (isStepBack(webSecureEntrypointPort)) {
            return 'back';
        }
        draft.webSecureEntrypointPort = webSecureEntrypointPort;
        return 'next';
    }, async (canBack) => {
        const smtpPort = await promptPort({
            initialValue: draft.smtpPort ?? draft.existingConfig?.SMTP_PORT ?? env_loader_1.DEFAULT_ENV.SMTP_PORT,
            allowOccupiedValue: draft.existingConfig?.SMTP_PORT,
            message: childPrompt(activeT('setup.mailpit.prompt')),
            canBack,
            frame: { description: activeT('setup.mailpit.description') }
        });
        if (isStepBack(smtpPort)) {
            return 'back';
        }
        draft.smtpPort = smtpPort;
        return 'next';
    }, async (canBack) => {
        const installMkcert = await promptConfirm({
            message: activeT('setup.localCa.prompt'),
            active: activeT('common.yes'),
            inactive: activeT('common.no'),
            initialValue: draft.installMkcert ??
                (draft.existingConfig ? draft.existingConfig.MKCERT_INSTALLED === 'true' : true),
            canBack,
            frame: { description: activeT('setup.localCa.description') }
        });
        if (isStepBack(installMkcert)) {
            return 'back';
        }
        draft.installMkcert = installMkcert;
        return 'next';
    });
    let stepIndex = 0;
    while (true) {
        while (stepIndex < steps.length) {
            const stepResult = await steps[stepIndex](stepIndex > 0);
            stepIndex += stepResult === 'back' ? -1 : 1;
        }
        const reviewAction = await promptReview(draft);
        if (reviewAction === 'apply') {
            break;
        }
        if (reviewAction === 'cancel') {
            p.cancel(activeT('setup.cancelled'));
            process.exit(0);
        }
        stepIndex = Math.max(steps.length - 1, 0);
    }
    const configToWrite = setupConfigInput(draft);
    const spinner = p.spinner();
    spinner.start(activeT('setup.writingFiles'));
    env_loader_1.envLoader.write(draft.envPath, configToWrite);
    const config = env_loader_1.envLoader.load(draft.envPath, draft.projectDir);
    (0, project_files_1.ensureProjectFiles)(config, { overwriteCompose: true });
    tool_state_1.toolState.writeSetupState({ runestonePath: draft.projectDir, locale: draft.selectedLocale });
    spinner.stop(activeT('setup.configurationWritten', { envPath: draft.envPath }));
    if (draft.installMkcert) {
        const caSpinner = p.spinner();
        caSpinner.start(activeT('setup.localCa.spinner'));
        await createDefaultCertificates(config.PROJECT_DIR, config.HOST_DOMAIN);
        caSpinner.stop(activeT('setup.localCa.done'));
    }
    if (settingsChanged(draft.existingConfig, configToWrite)) {
        const restart = cancelIfNeeded(await p.confirm({
            message: activeT('setup.restart.prompt'),
            active: activeT('common.yes'),
            inactive: activeT('common.no'),
            initialValue: true
        }));
        if (restart) {
            const running = docker_compose_1.composeService.ps(config.COMPOSE_FILE_PATH).some((container) => container.State === 'running');
            if (running) {
                const restartSpinner = p.spinner();
                restartSpinner.start(activeT('setup.restart.spinner'));
                docker_compose_1.composeService.restart(config.COMPOSE_FILE_PATH);
                restartSpinner.stop(activeT('setup.restart.done'));
            }
            else {
                p.log.warn(activeT('setup.restart.notRunning'));
            }
        }
    }
    p.log.success(activeT('setup.result.path', { path: config.PROJECT_DIR }));
    p.log.success(activeT('setup.result.compose', { path: config.COMPOSE_FILE_PATH }));
    p.log.success(activeT('setup.result.domain', { domain: config.HOST_DOMAIN }));
    p.outro(activeT('setup.outro'));
    return env_loader_1.envLoader.load(draft.envPath, draft.projectDir);
}
function createSetupCommand() {
    return (0, command_1.createCommand)('setup')
        .description((0, i18n_1.t)('commands.setup.description'))
        .action(async () => {
        try {
            await runSetup();
        }
        catch (error) {
            const message = error instanceof Error ? error.message : String(error);
            p.cancel(activeT('setup.failed', { message }));
            process.exit(1);
        }
    });
}
//# sourceMappingURL=setup.js.map