"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSpecArchiveCommand = createSpecArchiveCommand;
const errors_1 = require("../../../lib/errors");
const output_1 = require("../../../lib/output");
const global_format_1 = require("../global-format");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
const spec_registry_1 = require("../../../lib/spec-registry");
const transaction_1 = require("../../../lib/spec-registry/transaction");
const path_resolution_1 = require("../../../lib/spec-registry/path-resolution");
async function createSpecArchiveCommand() {
    const { Command } = await import('commander');
    const command = new Command('archive');
    command
        .description('Archive an active spec entry without removing it from the registry.')
        .argument('<id>', 'Registered spec id to archive.')
        .action((entryId, _, commandInstance) => {
        const format = (0, output_1.resolveOutputFormat)((0, global_format_1.getGlobalFormat)(commandInstance));
        if (format === null) {
            throw (0, errors_1.createUsageError)('Output format must be one of: text, json.', [
                `Received: ${String((0, global_format_1.getGlobalFormat)(commandInstance))}`,
            ]);
        }
        const repositoryContext = (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false);
        const specIndexPaths = (0, path_resolution_1.resolveSpecIndexPaths)(repositoryContext);
        const currentSnapshot = (0, transaction_1.readSpecRegistrySnapshotSync)(repositoryContext.root);
        const currentIndex = currentSnapshot.document;
        const archiveResult = (0, spec_registry_1.applySpecRegistryArchive)({
            entryId,
            currentDocument: currentIndex,
        });
        if (!archiveResult.ok) {
            throw new errors_1.RuntimeError({
                message: 'Spec archive validation failed.',
                code: 'SPEC_ARCHIVE_VALIDATION_FAILED',
                exitCode: errors_1.RuntimeExitCode.ERROR,
                details: archiveResult.findings.map((finding) => finding.message),
                findings: [...archiveResult.findings],
            });
        }
        requireCommittedRegistryMutation('archive', (0, transaction_1.commitSpecRegistryDocumentSync)(repositoryContext.root, {
            expectedRevision: currentSnapshot.revision,
            document: archiveResult.document,
        }));
        (0, output_1.emitSuccess)({
            command: 'spec archive',
            format,
            text: renderSpecArchiveWriteText(archiveResult.entry.id),
            data: {
                repositoryRoot: repositoryContext.root,
                detectionSource: repositoryContext.detectionSource,
                specIndexPath: specIndexPaths.relativePath,
                entry: archiveResult.entry,
            },
        });
    });
    return command;
}
function requireCommittedRegistryMutation(operation, mutation) {
    if (mutation.outcome === 'committed')
        return;
    if (mutation.outcome === 'conflict') {
        throw new errors_1.RuntimeError({
            message: `Spec ${operation} could not commit because the registry changed concurrently.`,
            code: 'SPEC_REGISTRY_CONCURRENCY_CONFLICT',
            exitCode: errors_1.RuntimeExitCode.CONCURRENCY_CONFLICT,
            details: [mutation.conflict?.message ?? 'Refresh the registry and retry the command.'],
        });
    }
    if (mutation.outcome === 'incomplete') {
        throw new errors_1.RuntimeError({
            message: `Spec ${operation} registry transaction is incomplete.`,
            code: 'SPEC_REGISTRY_TRANSACTION_INCOMPLETE',
            exitCode: errors_1.RuntimeExitCode.PARTIAL_MUTATION,
            details: [mutation.failure ?? 'Inspect retained registry transaction evidence before recovery.'],
            recoveryActions: [(0, errors_1.createNonCallableRecoveryAction)({
                    id: 'recovery.spec-registry.transaction.inspect',
                    command: null,
                    explanation: 'Inspect the retained registry transaction before retrying the mutation.',
                    reason: mutation.recoveryPath === null
                        ? 'No callable registry recovery command is currently available.'
                        : `Retained transaction evidence: ${mutation.recoveryPath}.`,
                })],
        });
    }
    throw new errors_1.RuntimeError({
        message: `Spec ${operation} registry transaction did not write.`,
        code: 'SPEC_REGISTRY_WRITE_FAILED',
        exitCode: errors_1.RuntimeExitCode.ERROR,
        details: [mutation.failure ?? 'Refresh the registry and retry the command.'],
    });
}
function renderSpecArchiveWriteText(entryId) {
    return ['Archived spec entry.', `Entry id: ${entryId}`].join('\n');
}
