"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTemplateReconcileCommand = createTemplateReconcileCommand;
const errors_1 = require("../../../lib/errors");
const output_1 = require("../../../lib/output");
const template_reconciliation_1 = require("../../../lib/templates/template-reconciliation");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
const registration_1 = require("../registration");
async function createTemplateReconcileCommand() {
    const { Command } = await import("commander");
    const command = new Command("reconcile");
    command.description("Preview or apply an explicit packaged-template reconciliation decision.");
    (0, registration_1.registerCommand)(command, await createTemplateReconcilePreviewCommand());
    (0, registration_1.registerCommand)(command, await createTemplateReconcileApplyCommand());
    return command;
}
async function createTemplateReconcilePreviewCommand() {
    const { Command } = await import("commander");
    return new Command("preview")
        .description("Compare one workspace template with its packaged source without writing.")
        .requiredOption("--template <path>", "Repository-relative packaged workspace template path.")
        .action((_, commandInstance) => {
        const context = readCommandContext(commandInstance);
        const requestedTemplatePath = readRequiredString(commandInstance.opts().template, "--template");
        const plan = createPlanOrUsageError({
            repositoryRoot: context.repositoryRoot,
            requestedTemplatePath
        });
        (0, output_1.emitSuccess)({
            command: "template reconcile preview",
            format: context.format,
            text: renderReconcileText(plan, null, false, [], null),
            data: {
                repositoryRoot: context.repositoryRoot,
                detectionSource: context.detectionSource,
                reconciliation: plan,
                readOnly: true,
                writeApplied: false
            }
        });
    });
}
async function createTemplateReconcileApplyCommand() {
    const { Command } = await import("commander");
    return new Command("apply")
        .description("Apply a preview-bound preserve or replace decision to one template.")
        .requiredOption("--template <path>", "Repository-relative packaged workspace template path.")
        .requiredOption("--decision <decision>", "Explicit decision: preserve or replace.")
        .requiredOption("--preview-hash <sha256>", "Exact hash returned by template reconcile preview.")
        .action((_, commandInstance) => {
        const context = readCommandContext(commandInstance);
        const options = commandInstance.opts();
        const decision = parseDecision(options.decision);
        let result;
        try {
            result = (0, template_reconciliation_1.applyTemplateReconciliationPlanSync)({
                repositoryRoot: context.repositoryRoot,
                requestedTemplatePath: readRequiredString(options.template, "--template"),
                decision,
                previewHash: readRequiredString(options.previewHash, "--preview-hash")
            });
        }
        catch (error) {
            throw reconciliationError(error);
        }
        (0, output_1.emitSuccess)({
            command: "template reconcile apply",
            format: context.format,
            text: renderReconcileText(result.plan, result.decision, result.writeApplied, result.updatedPaths, result.transaction?.outcome ?? "no-op"),
            data: {
                repositoryRoot: context.repositoryRoot,
                detectionSource: context.detectionSource,
                reconciliation: result.plan,
                decision: result.decision,
                transactionOutcome: result.transaction?.outcome ?? "no-op",
                writeApplied: result.writeApplied,
                updatedPaths: result.updatedPaths
            }
        });
    });
}
function readCommandContext(commandInstance) {
    const format = (0, output_1.resolveOutputFormat)(commandInstance.optsWithGlobals().format);
    if (format === null) {
        throw (0, errors_1.createUsageError)("Output format must be one of: text, json.", []);
    }
    const repositoryContext = (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false);
    return {
        repositoryRoot: repositoryContext.root,
        detectionSource: repositoryContext.detectionSource,
        format
    };
}
function createPlanOrUsageError(options) {
    try {
        return (0, template_reconciliation_1.createTemplateReconciliationPlan)(options);
    }
    catch (error) {
        throw reconciliationError(error);
    }
}
function reconciliationError(error) {
    if (error instanceof template_reconciliation_1.TemplateReconciliationTransactionError) {
        if (error.result.outcome === "incomplete") {
            return new errors_1.RuntimeError({
                message: error.message,
                code: "TEMPLATE_RECONCILIATION_PARTIAL",
                exitCode: errors_1.RuntimeExitCode.PARTIAL_MUTATION,
                writeOutcome: "partial",
                details: [
                    `Recovery transaction: ${error.result.transactionPath}`,
                    ...(error.result.failure === null ? [] : [error.result.failure])
                ],
                recoveryActions: [(0, errors_1.createNonCallableRecoveryAction)({
                        id: "recovery.inspect-template-transaction",
                        explanation: "Inspect the retained repository transaction before retrying reconciliation.",
                        reason: "Partial replacement state requires operator inspection before another write.",
                        expectedPostcondition: "The selected template and retained transaction evidence agree."
                    })]
            });
        }
        if (error.result.outcome === "conflict") {
            return new errors_1.RuntimeError({
                message: error.message,
                code: "TEMPLATE_RECONCILIATION_CONFLICT",
                exitCode: errors_1.RuntimeExitCode.CONCURRENCY_CONFLICT,
                details: error.result.conflicts.map((conflict) => `${conflict.path}: expected ${conflict.expectedState}; observed ${conflict.observedState}.`),
                recoveryActions: [(0, errors_1.createNonCallableRecoveryAction)({
                        id: "recovery.refresh-template-preview",
                        explanation: "Rerun template reconcile preview, then apply the new hash.",
                        reason: "A new preview hash must be supplied explicitly."
                    })]
            });
        }
    }
    return (0, errors_1.createUsageError)(error instanceof Error ? error.message : "Template reconciliation was rejected.", [
        "Rerun template reconcile preview after correcting the reported evidence.",
        "No implicit preserve or replace decision was made."
    ]);
}
function parseDecision(value) {
    const decision = typeof value === "string" ? value : "";
    if (!template_reconciliation_1.TEMPLATE_RECONCILIATION_DECISIONS.includes(decision)) {
        throw (0, errors_1.createUsageError)(`Unsupported template reconciliation decision '${String(value)}'.`, [`Supported decisions: ${template_reconciliation_1.TEMPLATE_RECONCILIATION_DECISIONS.join(", ")}.`]);
    }
    return decision;
}
function readRequiredString(value, option) {
    if (typeof value !== "string" || value.trim().length === 0) {
        throw (0, errors_1.createUsageError)(`${option} requires a non-empty value.`, []);
    }
    return value;
}
function renderReconcileText(plan, decision, writeApplied, updatedPaths, transactionOutcome) {
    return [
        (0, output_1.renderTerminalHeading)("Template Reconciliation", "title"),
        (0, output_1.renderTerminalSection)({
            heading: "Summary",
            fields: [
                { label: "Template", value: plan.templatePath },
                { label: "Drift state", value: plan.classification.state },
                { label: "Needs replacement", value: plan.classification.replacementNeeded },
                { label: "Preview hash", value: plan.previewHash },
                { label: "Allowed decisions", value: plan.allowedDecisions.join(", ") },
                { label: "Applied decision", value: decision ?? "preview only" },
                { label: "Transaction outcome", value: transactionOutcome ?? "preview only" }
            ]
        }),
        "",
        (0, output_1.renderTerminalSection)({
            heading: "Hash Evidence",
            fields: [
                { label: "Workspace", value: plan.classification.workspaceSha256 ?? "(missing)" },
                { label: "Packaged", value: plan.classification.packagedSha256 }
            ]
        }),
        "",
        (0, output_1.renderTerminalSection)({
            heading: "Write Boundary",
            lines: [
                writeApplied
                    ? (0, output_1.renderTerminalBoundary)({ kind: "write-applied", target: updatedPaths.join(", ") })
                    : decision === "preserve"
                        ? (0, output_1.renderTerminalBoundary)({
                            kind: "mutating-no-op",
                            reason: "The explicit preserve decision leaves workspace content unchanged."
                        })
                        : (0, output_1.renderTerminalBoundary)({ kind: "dry-run" })
            ]
        })
    ].join("\n");
}
