"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createWorkspaceMigrateCommand = createWorkspaceMigrateCommand;
const errors_1 = require("../../../lib/errors");
const output_1 = require("../../../lib/output");
const workspace_compatibility_1 = require("../../../lib/workspace-compatibility");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
const global_format_1 = require("../global-format");
async function createWorkspaceMigrateCommand() {
    const { Command } = await import("commander");
    const command = new Command("migrate");
    command
        .description("Plan or apply explicit Day Shift workspace metadata migrations.")
        .requiredOption("--target-schema-version <version>", "Supported target schema version for workspace metadata.")
        .option("--dry-run", "Report the migration plan without writing files.")
        .option("--confirm <token>", "Required write confirmation token: apply-workspace-migration.")
        .option("--family <family>", "Migration family. Only full workspace migrations are currently supported.")
        .option("--field <field>", "Rejected partial field migration request; use full workspace migration instead.")
        .action((_, 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 commandOptions = commandInstance.opts();
        const targetSchemaVersion = parseTargetSchemaVersion(commandOptions.targetSchemaVersion);
        rejectUnsafeMigrationRequest({
            targetSchemaVersion,
            family: commandOptions.family,
            field: commandOptions.field
        });
        const repositoryContext = (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false);
        const migration = commandOptions.dryRun
            ? requireRunnableMigration((0, workspace_compatibility_1.planWorkspaceSchemaMigration)({
                repositoryRoot: repositoryContext.root,
                targetSchemaVersion
            }))
            : applyConfirmedMigration({
                repositoryRoot: repositoryContext.root,
                targetSchemaVersion,
                confirm: commandOptions.confirm
            });
        (0, output_1.emitSuccess)({
            command: "workspace migrate",
            format,
            text: renderWorkspaceMigrationPlanText(migration),
            data: {
                repositoryRoot: repositoryContext.root,
                detectionSource: repositoryContext.detectionSource,
                migration
            }
        });
    });
    return command;
}
function rejectUnsafeMigrationRequest(options) {
    if (options.targetSchemaVersion < 1) {
        throw createWorkspaceMigrationRejectedError({
            category: "unsupported-target",
            detail: `Target schema version ${options.targetSchemaVersion} is not supported.`,
            requestedTarget: String(options.targetSchemaVersion)
        });
    }
    if (typeof options.family === "string" && options.family !== "workspace") {
        throw createWorkspaceMigrationRejectedError({
            category: "cross-family",
            detail: `Migration family '${options.family}' is not supported by workspace migration.`,
            requestedTarget: options.family
        });
    }
    if (typeof options.field === "string" && options.field.trim().length > 0) {
        throw createWorkspaceMigrationRejectedError({
            category: "partial-request",
            detail: `Partial field migration '${options.field}' is not supported.`,
            requestedTarget: options.field
        });
    }
}
function requireRunnableMigration(migration) {
    if (migration.status !== "blocked") {
        return migration;
    }
    const firstBlocked = migration.blockedArtifacts[0];
    throw createWorkspaceMigrationRejectedError({
        category: firstBlocked?.reason ?? "blocked-plan",
        detail: firstBlocked?.message ?? "Workspace migration plan is blocked.",
        requestedTarget: String(migration.targetSchemaVersion),
        path: firstBlocked?.path,
        evidenceDetails: {
            blockedArtifacts: migration.blockedArtifacts
        }
    });
}
function createWorkspaceMigrationRejectedError(options) {
    return (0, errors_1.createBlockingInvalidConfigError)({
        message: "Workspace migration request was rejected.",
        detail: options.detail,
        findingCode: "WORKSPACE_MIGRATION_REJECTED",
        findingMessage: options.detail,
        path: options.path,
        blockingReason: "invalid-command-input",
        recovery: "Rerun a full workspace migration with a supported target schema version after reviewing a dry-run plan. No files, backups, or checkpoints were written for this rejected request.",
        evidenceDetails: {
            category: options.category,
            requestedTarget: options.requestedTarget,
            noWriteBoundary: "No files, backups, or checkpoints were written.",
            ...(options.evidenceDetails ?? {})
        }
    });
}
function applyConfirmedMigration(options) {
    if (options.confirm !== "apply-workspace-migration") {
        throw createWorkspaceMigrationRejectedError({
            category: "missing-confirmation",
            detail: "Workspace migration writes require --confirm apply-workspace-migration.",
            requestedTarget: String(options.confirm ?? "(missing)")
        });
    }
    return requireRunnableMigration((0, workspace_compatibility_1.applyWorkspaceSchemaMigration)({
        repositoryRoot: options.repositoryRoot,
        targetSchemaVersion: options.targetSchemaVersion,
        backupRoot: `.day-shift/backups/workspace-migrations/${new Date().toISOString().replace(/[:.]/g, "-")}`
    }));
}
function parseTargetSchemaVersion(value) {
    const parsed = typeof value === "string" && /^\d+$/.test(value)
        ? Number.parseInt(value, 10)
        : Number.NaN;
    if (!Number.isSafeInteger(parsed)) {
        throw (0, errors_1.createUsageError)("Target schema version must be a positive integer.", [`Received: ${String(value)}`]);
    }
    return parsed;
}
function renderWorkspaceMigrationPlanText(plan) {
    return [
        (0, output_1.renderTerminalHeading)("Workspace Migration Plan", "title"),
        (0, output_1.renderTerminalSection)({
            heading: "Summary",
            fields: [
                { label: "Status", value: plan.status },
                { label: "Target schema version", value: plan.targetSchemaVersion },
                { label: "Dry-run", value: plan.dryRun ? "yes" : "no" },
                { label: "Write applied", value: "writeApplied" in plan && plan.writeApplied ? "yes" : "no" },
                { label: "Planned changes", value: plan.changes.length },
                { label: "Skipped artifacts", value: plan.skippedArtifacts.length },
                { label: "Blocked artifacts", value: plan.blockedArtifacts.length }
            ]
        }),
        "",
        (0, output_1.renderTerminalCompactList)({
            heading: "Planned Artifact Changes",
            entries: plan.changes.map((change) => ({
                label: change.path,
                fields: [
                    { label: "Family", value: change.family },
                    { label: "Field", value: change.field },
                    { label: "Version", value: `${change.fromVersion} -> ${change.toVersion}` },
                    { label: "Backup path", value: change.backupPath },
                    { label: "Coordinated fields", value: change.coordinatedFields.join(", ") }
                ]
            })),
            emptyMessage: "No artifact changes are planned."
        }),
        "",
        (0, output_1.renderTerminalCompactList)({
            heading: "Skipped Artifacts",
            entries: plan.skippedArtifacts.map((artifact) => ({
                label: artifact.path,
                fields: [
                    { label: "Family", value: artifact.family },
                    { label: "Field", value: artifact.field },
                    { label: "Reason", value: artifact.reason }
                ]
            })),
            emptyMessage: "No artifacts were skipped."
        }),
        "",
        (0, output_1.renderTerminalCompactList)({
            heading: "Blocked Artifacts",
            entries: plan.blockedArtifacts.map((artifact) => ({
                label: artifact.path,
                fields: [
                    { label: "Family", value: artifact.family },
                    { label: "Field", value: artifact.field },
                    { label: "Reason", value: artifact.reason },
                    { label: "Message", value: artifact.message }
                ]
            })),
            emptyMessage: "No artifacts are blocked."
        }),
        "",
        "updatedArtifacts" in plan
            ? (0, output_1.renderTerminalCompactList)({
                heading: "Updated Artifacts",
                entries: plan.updatedArtifacts.map((artifactPath) => ({ label: artifactPath })),
                emptyMessage: "No artifacts were updated."
            })
            : "",
        "updatedArtifacts" in plan ? "" : "",
        "backupArtifacts" in plan
            ? (0, output_1.renderTerminalCompactList)({
                heading: "Backup Artifacts",
                entries: plan.backupArtifacts.map((artifactPath) => ({ label: artifactPath })),
                emptyMessage: "No backup artifacts were created."
            })
            : "",
        "backupArtifacts" in plan ? "" : "",
        (0, output_1.renderTerminalSection)({
            heading: "Write Boundary",
            lines: [
                plan.dryRun
                    ? (0, output_1.renderTerminalBoundary)({ kind: "dry-run" })
                    : plan.status === "no-op"
                        ? (0, output_1.renderTerminalBoundary)({
                            kind: "mutating-no-op",
                            reason: "Workspace already matched the requested schema migration target."
                        })
                        : (0, output_1.renderTerminalBoundary)({
                            kind: "write-applied",
                            target: "workspace migration",
                            targetLabel: "Write target"
                        })
            ]
        })
    ].join("\n");
}
