"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createVersionCommand = createVersionCommand;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const cli_constants_1 = require("../../../lib/config/cli-constants");
const errors_1 = require("../../../lib/errors");
const output_1 = require("../../../lib/output");
const command_contract_1 = require("../../../lib/version-manager/command-contract");
const doctor_1 = require("../../../lib/version-manager/doctor");
const license_resolution_1 = require("../../../lib/license/license-resolution");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
const install_1 = require("../../../lib/version-manager/install");
const selection_1 = require("../../../lib/version-manager/selection");
const state_layout_1 = require("../../../lib/version-manager/state-layout");
const uninstall_1 = require("../../../lib/version-manager/uninstall");
const global_format_1 = require("../global-format");
const registration_1 = require("../registration");
async function createVersionCommand() {
    const { Command } = await import('commander');
    const command = new Command('version');
    command
        .description('Manage installed Day Shift CLI versions through the existing day-shift command.')
        .addHelpText('after', [
        '',
        'Version manager boundary:',
        '  Manager operations are owned by day-shift version ... .',
        '  Normal day-shift invocations remain separate from this command family.',
        '  Install, selection, uninstall, and network availability behavior is introduced across later version-manager phases.',
        '',
        'Declared subcommands:',
        ...command_contract_1.VERSION_MANAGER_SUBCOMMANDS.map((name) => `  ${name}`),
    ].join('\n'));
    (0, registration_1.registerCommand)(command, createInstallCommand(Command));
    (0, registration_1.registerCommand)(command, createListCommand(Command));
    (0, registration_1.registerCommand)(command, createUseCommand(Command));
    (0, registration_1.registerCommand)(command, createPinCommand(Command));
    (0, registration_1.registerCommand)(command, createCurrentCommand(Command));
    (0, registration_1.registerCommand)(command, createUninstallCommand(Command));
    (0, registration_1.registerCommand)(command, createDoctorCommand(Command));
    (0, registration_1.registerCommand)(command, createCheckCommand(Command));
    (0, registration_1.registerCommand)(command, createAliasCommand(Command));
    return command;
}
function createInstallCommand(Command) {
    const command = new Command('install');
    command
        .description('Install a local Day Shift package source into version-manager state.')
        .option('--from <path>', 'Local release archive or unpacked package root.')
        .option('--assert-version <version>', 'Assert the exact package version before installing.')
        .action((_, commandInstance) => {
        const options = commandInstance.opts();
        if (typeof options.from !== 'string' || options.from.trim() === '') {
            throw (0, errors_1.createUsageError)('Version install requires --from <path>.', [
                'Recovery: rerun with a local .tar.gz, .zip, or unpacked package root.',
            ]);
        }
        const requestedFormat = commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(commandInstance);
        const format = (0, output_1.resolveOutputFormat)(requestedFormat);
        if (format === null) {
            throw (0, errors_1.createUnsupportedOutputFormatError)({
                received: requestedFormat,
                commandBoundary: 'version install command output format',
            });
        }
        let result;
        try {
            result = (0, install_1.installManagedVersion)({
                sourcePath: options.from,
                assertedVersion: typeof options.assertVersion === 'string' ? options.assertVersion : undefined,
                env: process.env,
            });
        }
        catch (error) {
            throw (0, errors_1.createUsageError)('Version install source validation failed.', [
                error instanceof Error ? error.message : String(error),
                'No managed version state was mutated after validation failure.',
            ]);
        }
        (0, output_1.emitSuccess)({
            command: 'version install',
            format,
            text: renderVersionInstallResult(result),
            data: result,
        });
        getRootCommand(commandInstance ?? command).runtimeExitCode = errors_1.RuntimeExitCode.SUCCESS;
    });
    return command;
}
function _createDeferredSubcommand(Command, name, options) {
    const command = new Command(name);
    command.description(options.description);
    if (options.argument !== undefined) {
        command.argument(options.argument);
    }
    command.action((_, commandInstance) => {
        emitVersionContract(commandInstance ?? command, (0, command_contract_1.createDeferredVersionCommandContract)({
            command: `version ${name}`,
            operation: options.operation,
        }));
    });
    return command;
}
function renderVersionInstallResult(result) {
    return (0, output_1.renderTerminalSection)({
        heading: 'Day Shift version install',
        headingStyle: 'title',
        fields: [
            { label: 'Version', value: result.version },
            { label: 'Version manager root', value: result.versionManagerRoot },
            { label: 'Managed package', value: result.managedPackageDirectory },
            { label: 'Metadata', value: result.metadataPath },
            { label: 'Receipt', value: result.receiptPath },
            { label: 'Replaced existing package', value: result.replacedExistingPackage },
            { label: 'Checksum status', value: result.checksumStatus },
            { label: 'Network attempted', value: result.networkAttempted },
        ],
    });
}
function createListCommand(Command) {
    const command = new Command('list');
    command
        .description('List locally installed Day Shift versions with offline license summaries.')
        .action((_, commandInstance) => {
        const requestedFormat = commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(commandInstance);
        const format = (0, output_1.resolveOutputFormat)(requestedFormat);
        if (format === null) {
            throw (0, errors_1.createUnsupportedOutputFormatError)({
                received: requestedFormat,
                commandBoundary: 'version list command output format',
            });
        }
        const result = listManagedVersions({
            env: process.env,
        });
        (0, output_1.emitSuccess)({
            command: 'version list',
            format,
            text: renderVersionListResult(result),
            data: result,
        });
        getRootCommand(commandInstance ?? command).runtimeExitCode = errors_1.RuntimeExitCode.SUCCESS;
    });
    return command;
}
function listManagedVersions(options) {
    const versionManagerRoot = (0, state_layout_1.resolveVersionManagerRoot)({ env: options.env });
    const repositoryContext = (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false);
    const installedVersions = (0, selection_1.listInstalledVersions)(versionManagerRoot).map((installedVersion) => {
        const licenseStatus = (0, license_resolution_1.resolveLicenseStatus)({
            repositoryContext,
            env: options.env,
            currentCliVersion: installedVersion.version,
        });
        return {
            ...installedVersion,
            license: {
                effective_status: licenseStatus.effective_status,
                reason_code: licenseStatus.reason_code,
                covered_release_line: licenseStatus.covered_release_line,
                current_version_coverage_state: licenseStatus.current_version_coverage_state,
                effective_coverage_path: licenseStatus.effective_coverage_path,
                license_path: licenseStatus.license_path,
            },
        };
    });
    return {
        versionManagerRoot,
        installedVersions,
        count: installedVersions.length,
        networkAttempted: false,
        readOnly: true,
    };
}
function renderVersionListResult(result) {
    return [
        (0, output_1.renderTerminalSection)({
            heading: 'Day Shift version list',
            headingStyle: 'title',
            fields: [
                { label: 'Version manager root', value: result.versionManagerRoot },
                { label: 'Installed versions', value: result.count },
                { label: 'Network attempted', value: result.networkAttempted },
                { label: 'Read only', value: result.readOnly },
            ],
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: 'Installed versions',
            headingStyle: 'section',
            entries: result.installedVersions.map((entry) => ({
                label: entry.version,
                fields: [
                    { label: 'Version directory', value: entry.versionDirectory },
                    { label: 'Package', value: entry.packageDirectory },
                    { label: 'License status', value: entry.license.effective_status },
                    { label: 'License reason', value: entry.license.reason_code },
                    { label: 'Covered release line', value: entry.license.covered_release_line },
                    { label: 'Coverage state', value: entry.license.current_version_coverage_state },
                    { label: 'Coverage path', value: entry.license.effective_coverage_path },
                    { label: 'License path', value: entry.license.license_path },
                ],
            })),
            emptyMessage: '(none)',
        }),
        (0, output_1.renderTerminalBoundary)({ kind: 'read-only' }),
    ].join('\n\n');
}
function createUninstallCommand(Command) {
    const command = new Command('uninstall');
    command
        .description('Uninstall one managed Day Shift version.')
        .argument('[version]')
        .option('--replace-with <version>', 'Replace affected selectors with another exact installed version before uninstalling.')
        .option('--confirm-selected-removal', 'Confirm uninstall even when selectors point at the removed version.')
        .action((version, _, commandInstance) => {
        const options = commandInstance.opts();
        const requestedFormat = commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(commandInstance);
        const format = (0, output_1.resolveOutputFormat)(requestedFormat);
        if (format === null) {
            throw (0, errors_1.createUnsupportedOutputFormatError)({
                received: requestedFormat,
                commandBoundary: 'version uninstall command output format',
            });
        }
        const result = (0, uninstall_1.uninstallManagedVersion)({
            target: version,
            env: process.env,
            cwd: process.cwd(),
            replacementVersion: typeof options.replaceWith === 'string' ? options.replaceWith : undefined,
            confirmSelectedRemoval: options.confirmSelectedRemoval === true,
        });
        if (!result.ok) {
            emitVersionUninstallValidationFailure({
                commandInstance,
                command,
                format,
                result,
            });
            return;
        }
        (0, output_1.emitSuccess)({
            command: 'version uninstall',
            format,
            text: renderVersionUninstallResult(result),
            data: result,
        });
        getRootCommand(commandInstance ?? command).runtimeExitCode = errors_1.RuntimeExitCode.SUCCESS;
    });
    return command;
}
function emitVersionUninstallValidationFailure(options) {
    (0, output_1.emitError)({
        command: 'version uninstall',
        format: options.format,
        code: 'USAGE_ERROR',
        message: options.result.message,
        details: options.result.details,
        data: options.result,
    });
    getRootCommand(options.commandInstance ?? options.command).runtimeExitCode = errors_1.RuntimeExitCode.USAGE;
}
function renderVersionUninstallResult(result) {
    return [
        (0, output_1.renderTerminalSection)({
            heading: 'Day Shift version uninstall',
            headingStyle: 'title',
            fields: [
                { label: 'Target version', value: result.target },
                { label: 'Version manager root', value: result.versionManagerRoot },
                { label: 'Version directory', value: result.versionDirectory },
                { label: 'Removed version directory', value: result.removedVersionDirectory },
                { label: 'Receipts directory', value: result.receiptsDirectory },
                { label: 'Replacement version', value: result.replacementVersion ?? '(none)' },
                { label: 'Replacement applied', value: result.replacementApplied },
                { label: 'Confirmed selected removal', value: result.confirmedSelectedRemoval },
                { label: 'Written', value: result.written },
            ],
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: 'Affected selectors',
            headingStyle: 'section',
            entries: result.affectedSelectors.map((selector) => ({
                label: selector.label,
                fields: [
                    { label: 'Kind', value: selector.kind },
                    { label: 'Selector', value: selector.selector },
                    { label: 'Path', value: selector.path },
                ],
            })),
            emptyMessage: '(none)',
        }),
        (0, output_1.renderTerminalPathBlock)({
            heading: 'Removed receipts',
            headingStyle: 'section',
            paths: result.removedReceiptPaths,
            emptyMessage: '(none)',
        }),
        (0, output_1.renderTerminalPathBlock)({
            heading: 'Preserved receipts',
            headingStyle: 'section',
            paths: result.preservedReceiptPaths,
            emptyMessage: '(none)',
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: 'Preserved state',
            headingStyle: 'section',
            entries: result.preservedState.map((entry) => ({ label: entry })),
            emptyMessage: '(none)',
        }),
        (0, output_1.renderTerminalBoundary)({
            kind: 'write-applied',
            target: result.versionDirectory,
            targetLabel: 'Managed version directory',
            stateSurface: 'version-manager managed package state',
        }),
    ].join('\n\n');
}
function createCurrentCommand(Command) {
    const command = new Command('current');
    command
        .description('Show the currently selected Day Shift version.')
        .action((_, commandInstance) => {
        const requestedFormat = commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(commandInstance);
        const format = (0, output_1.resolveOutputFormat)(requestedFormat);
        if (format === null) {
            throw (0, errors_1.createUnsupportedOutputFormatError)({
                received: requestedFormat,
                commandBoundary: 'version current command output format',
            });
        }
        const selection = (0, selection_1.resolveManagedVersionSelection)({
            env: process.env,
            cwd: process.cwd(),
        });
        const result = {
            ...selection,
            readOnly: true,
            networkAttempted: false,
        };
        (0, output_1.emitSuccess)({
            command: 'version current',
            format,
            text: renderVersionCurrentResult(result),
            data: result,
        });
        getRootCommand(commandInstance ?? command).runtimeExitCode = result.ok
            ? errors_1.RuntimeExitCode.SUCCESS
            : errors_1.RuntimeExitCode.ERROR;
    });
    return command;
}
function createPinCommand(Command) {
    const command = new Command('pin');
    command
        .description('Write a repository Day Shift version pin.')
        .argument('<version>')
        .action((version, _, commandInstance) => {
        const requestedFormat = commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(commandInstance);
        const format = (0, output_1.resolveOutputFormat)(requestedFormat);
        if (format === null) {
            throw (0, errors_1.createUnsupportedOutputFormatError)({
                received: requestedFormat,
                commandBoundary: 'version pin command output format',
            });
        }
        if (!(0, selection_1.isExactStableVersion)(version)) {
            throw (0, errors_1.createUsageError)('Version pin requires an exact stable version.', [
                `Received selector: ${version}`,
                'Use major.minor.patch form, for example 0.1.0.',
                'Aliases, partial selectors, and latest-installed are not accepted for repository pins.',
            ]);
        }
        const result = writeRepositoryVersionPin({
            cwd: process.cwd(),
            version,
        });
        (0, output_1.emitSuccess)({
            command: 'version pin',
            format,
            text: renderVersionPinResult(result),
            data: result,
        });
        getRootCommand(commandInstance ?? command).runtimeExitCode = errors_1.RuntimeExitCode.SUCCESS;
    });
    return command;
}
function createUseCommand(Command) {
    const command = new Command('use');
    command
        .description('Set the global default Day Shift version.')
        .argument('<version>')
        .action((version, _, commandInstance) => {
        if (!(0, selection_1.isExactStableVersion)(version)) {
            throw (0, errors_1.createUsageError)('Version use requires an exact stable version.', [
                `Received selector: ${version}`,
                'Use day-shift version alias set default <selector> for alias or partial selector targets.',
            ]);
        }
        emitAliasWriteCommand({
            commandInstance: commandInstance ?? command,
            commandName: 'version use',
            aliasName: 'default',
            selector: version,
        });
    });
    return command;
}
function writeRepositoryVersionPin(options) {
    const workspaceRoot = findVersionPinWorkspaceRoot(options.cwd);
    const pinPath = node_path_1.default.join(workspaceRoot, '.day-shift-version');
    const previousSelector = node_fs_1.default.existsSync(pinPath) && node_fs_1.default.statSync(pinPath).isFile() ? node_fs_1.default.readFileSync(pinPath, 'utf8').trim() : null;
    node_fs_1.default.writeFileSync(pinPath, `${options.version}\n`);
    return {
        version: options.version,
        workspaceRoot,
        pinPath,
        previousSelector,
        selector: options.version,
        changed: previousSelector !== options.version,
        written: true,
    };
}
function findVersionPinWorkspaceRoot(cwd) {
    let currentDirectory = node_path_1.default.resolve(cwd);
    while (true) {
        if (node_fs_1.default.existsSync(node_path_1.default.join(currentDirectory, '.day-shift', 'config.toml')) ||
            node_fs_1.default.existsSync(node_path_1.default.join(currentDirectory, '.git'))) {
            return currentDirectory;
        }
        const parentDirectory = node_path_1.default.dirname(currentDirectory);
        if (parentDirectory === currentDirectory) {
            return node_path_1.default.resolve(cwd);
        }
        currentDirectory = parentDirectory;
    }
}
function writeVersionAlias(options) {
    validateAliasName(options.aliasName);
    validateAliasSelector(options.selector);
    const versionManagerRoot = (0, selection_1.resolveManagedVersionSelection)({ env: options.env }).versionManagerRoot;
    const aliasesDirectory = node_path_1.default.join(versionManagerRoot, 'aliases');
    const aliasPath = node_path_1.default.join(aliasesDirectory, options.aliasName);
    const previousSelector = node_fs_1.default.existsSync(aliasPath) && node_fs_1.default.statSync(aliasPath).isFile() ? node_fs_1.default.readFileSync(aliasPath, 'utf8').trim() : null;
    node_fs_1.default.mkdirSync(aliasesDirectory, { recursive: true });
    node_fs_1.default.writeFileSync(aliasPath, `${options.selector}\n`);
    return {
        aliasName: options.aliasName,
        selector: options.selector,
        aliasPath,
        previousSelector,
        changed: previousSelector !== options.selector,
        written: true,
    };
}
function listVersionAliases(env) {
    const versionManagerRoot = (0, selection_1.resolveManagedVersionSelection)({ env }).versionManagerRoot;
    const aliasesDirectory = node_path_1.default.join(versionManagerRoot, 'aliases');
    const aliases = node_fs_1.default.existsSync(aliasesDirectory)
        ? node_fs_1.default
            .readdirSync(aliasesDirectory, { withFileTypes: true })
            .filter((entry) => entry.isFile())
            .filter((entry) => /^[a-z][a-z0-9-]*$/.test(entry.name))
            .map((entry) => {
            const aliasPath = node_path_1.default.join(aliasesDirectory, entry.name);
            return {
                name: entry.name,
                selector: node_fs_1.default.readFileSync(aliasPath, 'utf8').trim(),
                path: aliasPath,
            };
        })
            .sort((left, right) => left.name.localeCompare(right.name))
        : [];
    return {
        versionManagerRoot,
        aliasesDirectory,
        aliases,
    };
}
function validateAliasName(aliasName) {
    if (!/^[a-z][a-z0-9-]*$/.test(aliasName)) {
        throw (0, errors_1.createUsageError)('Version alias name is invalid.', [
            `Received alias: ${aliasName}`,
            'Use a lowercase alias name with letters, digits, and hyphens.',
        ]);
    }
}
function validateAliasSelector(selector) {
    if (selector.trim() === '' || /[\\/]/.test(selector)) {
        throw (0, errors_1.createUsageError)('Version alias selector is invalid.', [
            'Alias selectors must be non-empty local selectors without path separators.',
        ]);
    }
}
function emitAliasWriteCommand(options) {
    const requestedFormat = options.commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(options.commandInstance);
    const format = (0, output_1.resolveOutputFormat)(requestedFormat);
    if (format === null) {
        throw (0, errors_1.createUnsupportedOutputFormatError)({
            received: requestedFormat,
            commandBoundary: `${options.commandName} command output format`,
        });
    }
    const result = writeVersionAlias({
        env: process.env,
        aliasName: options.aliasName,
        selector: options.selector,
    });
    (0, output_1.emitSuccess)({
        command: options.commandName,
        format,
        text: renderVersionAliasWriteResult(options.commandName, result),
        data: result,
    });
    getRootCommand(options.commandInstance).runtimeExitCode = errors_1.RuntimeExitCode.SUCCESS;
}
function renderVersionPinResult(result) {
    return [
        (0, output_1.renderTerminalSection)({
            heading: 'Day Shift version pin',
            headingStyle: 'title',
            fields: [
                { label: 'Version', value: result.version },
                { label: 'Workspace root', value: result.workspaceRoot },
                { label: 'Pin path', value: result.pinPath },
                { label: 'Previous selector', value: result.previousSelector ?? '(none)' },
                { label: 'Changed', value: result.changed },
            ],
        }),
        (0, output_1.renderTerminalBoundary)({
            kind: 'write-applied',
            target: result.pinPath,
            targetLabel: 'Pin file',
            stateSurface: '.day-shift-version',
        }),
    ].join('\n\n');
}
function renderVersionAliasWriteResult(commandName, result) {
    return [
        (0, output_1.renderTerminalSection)({
            heading: commandName,
            headingStyle: 'title',
            fields: [
                { label: 'Alias', value: result.aliasName },
                { label: 'Selector', value: result.selector },
                { label: 'Alias path', value: result.aliasPath },
                { label: 'Previous selector', value: result.previousSelector ?? '(none)' },
                { label: 'Changed', value: result.changed },
            ],
        }),
        (0, output_1.renderTerminalBoundary)({
            kind: 'write-applied',
            target: result.aliasPath,
            targetLabel: 'Alias file',
            stateSurface: 'version-manager aliases',
        }),
    ].join('\n\n');
}
function renderVersionAliasListResult(result) {
    return [
        (0, output_1.renderTerminalSection)({
            heading: 'Version aliases',
            headingStyle: 'title',
            fields: [
                { label: 'Version manager root', value: result.versionManagerRoot },
                { label: 'Aliases directory', value: result.aliasesDirectory },
                { label: 'Alias count', value: result.aliases.length },
            ],
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: 'Aliases',
            headingStyle: 'section',
            entries: result.aliases.map((entry) => ({
                label: entry.name,
                fields: [
                    { label: 'Selector', value: entry.selector },
                    { label: 'Path', value: entry.path },
                ],
            })),
            emptyMessage: '(none)',
        }),
    ].join('\n\n');
}
function renderVersionCurrentResult(result) {
    const summary = result.ok
        ? (0, output_1.renderTerminalSection)({
            heading: 'Day Shift version current',
            headingStyle: 'title',
            fields: [
                { label: 'Selected version', value: result.version },
                { label: 'Selection source', value: result.source },
                { label: 'Selector', value: result.selector },
                { label: 'Version manager root', value: result.versionManagerRoot },
                { label: 'Package', value: result.packageDirectory },
                { label: 'Metadata', value: result.metadataPath },
                { label: 'Read only', value: result.readOnly },
                { label: 'Network attempted', value: result.networkAttempted },
            ],
        })
        : (0, output_1.renderTerminalSection)({
            heading: 'Day Shift version current',
            headingStyle: 'title',
            fields: [
                { label: 'State', value: 'not selected' },
                { label: 'Reason', value: result.reason },
                { label: 'Version manager root', value: result.versionManagerRoot },
                { label: 'Source', value: result.source ?? '(none)' },
                { label: 'Selector', value: result.selector ?? '(none)' },
                { label: 'Read only', value: result.readOnly },
                { label: 'Network attempted', value: result.networkAttempted },
            ],
            lines: [result.message, ...result.details],
        });
    const installedVersions = (0, output_1.renderTerminalCompactList)({
        heading: 'Installed versions',
        headingStyle: 'section',
        entries: result.installedVersions.map((entry) => ({
            label: entry.version,
            fields: [
                { label: 'Version directory', value: entry.versionDirectory },
                { label: 'Package', value: entry.packageDirectory },
            ],
        })),
        emptyMessage: '(none)',
    });
    const diagnostics = (0, output_1.renderTerminalCompactList)({
        heading: 'Selection diagnostics',
        headingStyle: 'section',
        entries: result.diagnostics.map((diagnostic) => ({
            label: diagnostic.label,
            fields: [
                { label: 'Source', value: diagnostic.source },
                { label: 'Kind', value: diagnostic.kind },
                { label: 'Selector', value: diagnostic.selector ?? '(none)' },
                { label: 'Path', value: diagnostic.path ?? '(none)' },
            ],
            lines: [diagnostic.message],
        })),
        emptyMessage: '(none)',
    });
    return result.ok
        ? [summary, installedVersions, diagnostics].join('\n\n')
        : [
            summary,
            installedVersions,
            diagnostics,
            (0, output_1.renderTerminalBoundary)({ kind: 'no-write-failure', reason: result.reason }),
        ].join('\n\n');
}
function createCheckCommand(Command) {
    const command = new Command('check');
    command
        .description('Check Day Shift version availability only after explicit network approval.')
        .argument('[version]')
        .option('--network', 'Approve the declared network availability check.')
        .action(async (version, _, commandInstance) => {
        const requestedFormat = commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(commandInstance);
        const format = (0, output_1.resolveOutputFormat)(requestedFormat);
        if (format === null) {
            throw (0, errors_1.createUnsupportedOutputFormatError)({
                received: requestedFormat,
                commandBoundary: 'version check command output format',
            });
        }
        const options = commandInstance.opts();
        if (!options.network) {
            emitVersionContract(commandInstance ?? command, (0, command_contract_1.createNetworkApprovalRequiredContract)());
            return;
        }
        const result = await checkVersionAvailability({
            requestedVersion: typeof version === 'string' && version.trim() !== '' ? version.trim() : null,
            env: process.env,
        });
        (0, output_1.emitSuccess)({
            command: 'version check',
            format,
            text: renderVersionCheckResult(result),
            data: result,
        });
        getRootCommand(commandInstance ?? command).runtimeExitCode = errors_1.RuntimeExitCode.SUCCESS;
    });
    return command;
}
async function checkVersionAvailability(options) {
    const versionManagerRoot = (0, state_layout_1.resolveVersionManagerRoot)({ env: options.env });
    const installedVersions = (0, selection_1.listInstalledVersions)(versionManagerRoot);
    const metadataUrl = resolveVersionCheckMetadataUrl(options.env);
    const fixturePath = options.env.DAY_SHIFT_VERSION_CHECK_FIXTURE?.trim();
    if (fixturePath !== undefined && fixturePath !== '') {
        try {
            const parsed = parseReleaseManifestIndex(JSON.parse(node_fs_1.default.readFileSync(fixturePath, 'utf8')));
            if (!parsed.ok) {
                return {
                    state: 'metadata-malformed',
                    requestedVersion: options.requestedVersion,
                    available: null,
                    latestVersion: null,
                    metadataUrl: fixturePath,
                    metadataSource: 'local-test-fixture',
                    installedVersions,
                    networkAttempted: true,
                    noWrite: true,
                    details: parsed.details,
                    recovery: [
                        'Retry later after the Day Shift downloads manifest is corrected.',
                        'Continue using local installed-version state for offline workflows.',
                    ],
                };
            }
            return createVersionCheckResultFromManifest({
                requestedVersion: options.requestedVersion,
                metadataUrl: fixturePath,
                metadataSource: 'local-test-fixture',
                installedVersions,
                manifest: parsed,
            });
        }
        catch (error) {
            return metadataUnavailable({
                requestedVersion: options.requestedVersion,
                metadataUrl: fixturePath,
                metadataSource: 'local-test-fixture',
                installedVersions,
                detail: error instanceof Error ? error.message : String(error),
            });
        }
    }
    if (!metadataUrl.ok) {
        return {
            state: 'unsupported-metadata-source',
            requestedVersion: options.requestedVersion,
            available: null,
            latestVersion: null,
            metadataUrl: metadataUrl.url,
            metadataSource: null,
            installedVersions,
            networkAttempted: false,
            noWrite: true,
            details: metadataUrl.details,
            recovery: [
                'Use the default Day Shift-owned downloads manifest or a local test fixture endpoint.',
                'Continue using local installed-version state for offline workflows.',
            ],
        };
    }
    try {
        const response = await fetch(metadataUrl.url, {
            headers: { accept: 'application/json' },
        });
        if (!response.ok) {
            return metadataUnavailable({
                requestedVersion: options.requestedVersion,
                metadataUrl: metadataUrl.url,
                metadataSource: metadataUrl.source,
                installedVersions,
                detail: `HTTP ${response.status} ${response.statusText}`.trim(),
            });
        }
        const parsed = parseReleaseManifestIndex(await response.json());
        if (!parsed.ok) {
            return {
                state: 'metadata-malformed',
                requestedVersion: options.requestedVersion,
                available: null,
                latestVersion: null,
                metadataUrl: metadataUrl.url,
                metadataSource: metadataUrl.source,
                installedVersions,
                networkAttempted: true,
                noWrite: true,
                details: parsed.details,
                recovery: [
                    'Retry later after the Day Shift downloads manifest is corrected.',
                    'Continue using local installed-version state for offline workflows.',
                ],
            };
        }
        return createVersionCheckResultFromManifest({
            requestedVersion: options.requestedVersion,
            metadataUrl: metadataUrl.url,
            metadataSource: metadataUrl.source,
            installedVersions,
            manifest: parsed,
        });
    }
    catch (error) {
        return metadataUnavailable({
            requestedVersion: options.requestedVersion,
            metadataUrl: metadataUrl.url,
            metadataSource: metadataUrl.source,
            installedVersions,
            detail: error instanceof Error ? error.message : String(error),
        });
    }
}
function createVersionCheckResultFromManifest(options) {
    const available = options.requestedVersion === null
        ? true
        : options.manifest.versions.some((entry) => entry.version === options.requestedVersion && entry.available);
    return {
        state: available ? 'available' : 'unavailable',
        requestedVersion: options.requestedVersion,
        available,
        latestVersion: options.manifest.latestVersion,
        metadataUrl: options.metadataUrl,
        metadataSource: options.metadataSource,
        installedVersions: options.installedVersions,
        networkAttempted: true,
        noWrite: true,
        details: [
            `Manifest versions: ${options.manifest.versions.map((entry) => entry.version).join(', ') || '(none)'}`,
            options.requestedVersion === null
                ? 'No exact requested version was supplied; latest metadata was reported only.'
                : `Requested version ${options.requestedVersion} is ${available ? 'available' : 'not available'} in Day Shift metadata.`,
        ],
        recovery: [
            'Use local installed-version state for install, uninstall, selection, shim dispatch, and license workflows.',
            'Set aliases explicitly with day-shift version alias commands if a local selector should change.',
        ],
    };
}
function renderVersionCheckResult(result) {
    return [
        (0, output_1.renderTerminalSection)({
            heading: 'Day Shift version check',
            headingStyle: 'title',
            fields: [
                { label: 'State', value: result.state },
                { label: 'Requested version', value: result.requestedVersion ?? '(none)' },
                { label: 'Available', value: result.available === null ? '(unknown)' : result.available },
                { label: 'Latest version', value: result.latestVersion ?? '(unknown)' },
                { label: 'Metadata URL', value: result.metadataUrl ?? '(none)' },
                { label: 'Metadata source', value: result.metadataSource ?? '(none)' },
                { label: 'Network attempted', value: result.networkAttempted },
                { label: 'No write', value: result.noWrite },
            ],
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: 'Installed versions',
            headingStyle: 'section',
            entries: result.installedVersions.map((entry) => ({
                label: entry.version,
                fields: [
                    { label: 'Version directory', value: entry.versionDirectory },
                    { label: 'Package', value: entry.packageDirectory },
                ],
            })),
            emptyMessage: '(none)',
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: 'Details',
            headingStyle: 'section',
            entries: result.details.map((line) => ({ label: line })),
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: 'Recovery',
            headingStyle: 'section',
            entries: result.recovery.map((line) => ({ label: line })),
        }),
        (0, output_1.renderTerminalBoundary)({ kind: 'read-only' }),
    ].join('\n\n');
}
function metadataUnavailable(options) {
    return {
        state: 'metadata-unavailable',
        requestedVersion: options.requestedVersion,
        available: null,
        latestVersion: null,
        metadataUrl: options.metadataUrl,
        metadataSource: options.metadataSource,
        installedVersions: options.installedVersions,
        networkAttempted: true,
        noWrite: true,
        details: [options.detail],
        recovery: [
            'Retry the approved Day Shift-owned metadata check later.',
            'Continue using local installed-version state for offline workflows.',
        ],
    };
}
function resolveVersionCheckMetadataUrl(env) {
    const configured = env.DAY_SHIFT_VERSION_CHECK_URL?.trim();
    const rawUrl = configured && configured !== '' ? configured : `https://day-shift.dev/downloads/${cli_constants_1.RELEASE_MANIFEST_FILENAME}`;
    let parsed;
    try {
        parsed = new URL(rawUrl);
    }
    catch {
        return {
            ok: false,
            url: rawUrl,
            details: [`Version check metadata URL is malformed: ${rawUrl}`],
        };
    }
    const isDayShiftWebsite = parsed.protocol === 'https:' &&
        (parsed.hostname === 'day-shift.dev' || parsed.hostname === 'www.day-shift.dev') &&
        parsed.pathname.startsWith('/downloads/');
    const isLocalFixture = configured !== undefined &&
        parsed.protocol === 'http:' &&
        (parsed.hostname === '127.0.0.1' || parsed.hostname === 'localhost');
    if (isDayShiftWebsite) {
        return { ok: true, url: parsed.toString(), source: 'day-shift-website' };
    }
    if (isLocalFixture) {
        return { ok: true, url: parsed.toString(), source: 'local-test-fixture' };
    }
    return {
        ok: false,
        url: parsed.toString(),
        details: [
            'Version check metadata must come from the Day Shift-owned downloads manifest.',
            'GitHub, npm, public registry, and arbitrary provider URLs are not supported.',
        ],
    };
}
function parseReleaseManifestIndex(input) {
    if (typeof input !== 'object' || input === null) {
        return { ok: false, details: ['Release manifest index must be a JSON object.'] };
    }
    const document = input;
    if (!Array.isArray(document.versions)) {
        return { ok: false, details: ['Release manifest index must include versions[].'] };
    }
    const versions = [];
    for (const entry of document.versions) {
        if (typeof entry !== 'object' || entry === null) {
            return { ok: false, details: ['Release manifest version entries must be objects.'] };
        }
        const version = entry.version;
        const status = entry.status;
        if (typeof version !== 'string' || !(0, selection_1.isExactStableVersion)(version)) {
            return { ok: false, details: ['Release manifest version entries must include exact stable versions.'] };
        }
        versions.push({
            version,
            available: status === undefined || status === 'active' || status === 'deprecated',
        });
    }
    const latestVersion = typeof document.latest?.version === 'string' && (0, selection_1.isExactStableVersion)(document.latest.version)
        ? document.latest.version
        : (versions.at(-1)?.version ?? null);
    return { ok: true, latestVersion, versions };
}
function createDoctorCommand(Command) {
    const command = new Command('doctor');
    command
        .description('Inspect local version-manager runtime context.')
        .action((_, commandInstance) => {
        const requestedFormat = commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(commandInstance);
        const format = (0, output_1.resolveOutputFormat)(requestedFormat);
        if (format === null) {
            throw (0, errors_1.createUnsupportedOutputFormatError)({
                received: requestedFormat,
                commandBoundary: 'version doctor command output format',
            });
        }
        const report = (0, doctor_1.createVersionDoctorReport)(process.env);
        (0, output_1.emitSuccess)({
            command: 'version doctor',
            format,
            text: (0, doctor_1.renderVersionDoctorReport)(report, format),
            data: report,
        });
        getRootCommand(commandInstance ?? command).runtimeExitCode = errors_1.RuntimeExitCode.SUCCESS;
    });
    return command;
}
function createAliasCommand(Command) {
    const command = new Command('alias');
    command
        .description('Inspect or mutate local version aliases.')
        .addHelpText('after', ['', 'Alias operations:', '  list', '  set <name> <version>'].join('\n'));
    const listCommand = new Command('list');
    listCommand.description('List local version aliases.').action((_, commandInstance) => {
        const requestedFormat = commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(commandInstance);
        const format = (0, output_1.resolveOutputFormat)(requestedFormat);
        if (format === null) {
            throw (0, errors_1.createUnsupportedOutputFormatError)({
                received: requestedFormat,
                commandBoundary: 'version alias list command output format',
            });
        }
        const result = listVersionAliases(process.env);
        (0, output_1.emitSuccess)({
            command: 'version alias list',
            format,
            text: renderVersionAliasListResult(result),
            data: result,
        });
        getRootCommand(commandInstance ?? command).runtimeExitCode = errors_1.RuntimeExitCode.SUCCESS;
    });
    (0, registration_1.registerCommand)(command, listCommand);
    const setCommand = new Command('set');
    setCommand
        .description('Set a local version alias.')
        .argument('<name>')
        .argument('<version>')
        .action((name, version, _, commandInstance) => {
        emitAliasWriteCommand({
            commandInstance: commandInstance ?? command,
            commandName: 'version alias set',
            aliasName: name,
            selector: version,
        });
    });
    (0, registration_1.registerCommand)(command, setCommand);
    command.action((_, commandInstance) => {
        emitVersionContract(commandInstance ?? command, (0, command_contract_1.createDeferredVersionCommandContract)({
            command: 'version alias',
            operation: 'alias',
        }));
    });
    return command;
}
function emitVersionContract(commandInstance, contract) {
    const requestedFormat = commandInstance.optsWithGlobals?.().format ?? (0, global_format_1.getGlobalFormat)(commandInstance);
    const format = (0, output_1.resolveOutputFormat)(requestedFormat);
    if (format === null) {
        throw (0, errors_1.createUnsupportedOutputFormatError)({
            received: requestedFormat,
            commandBoundary: `${contract.command} command output format`,
        });
    }
    (0, output_1.emitSuccess)({
        command: contract.command,
        format,
        text: (0, command_contract_1.renderVersionCommandContract)(contract, format),
        data: (0, command_contract_1.toVersionCommandContractData)(contract),
    });
    getRootCommand(commandInstance).runtimeExitCode = contract.exitCode;
}
function getRootCommand(commandInstance) {
    let current = commandInstance;
    while (current.parent !== undefined && current.parent !== null) {
        current = current.parent;
    }
    return current;
}
