"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPromptEditCommand = createPromptEditCommand;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const node_child_process_1 = require("node:child_process");
const config_contract_1 = require("../../../lib/config/config-contract");
const config_store_1 = require("../../../lib/config/config-store");
const config_layer_resolution_1 = require("../../../lib/config/config-layer-resolution");
const errors_1 = require("../../../lib/errors");
const output_1 = require("../../../lib/output");
const paths_1 = require("../../../lib/paths");
const prompt_version_evidence_1 = require("../../../lib/prompts/prompt-version-evidence");
const prompt_rendering_evidence_1 = require("../../../lib/prompts/prompt-rendering-evidence");
const prompt_materialization_1 = require("../../../lib/prompts/prompt-materialization");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
const global_format_1 = require("../global-format");
const path_utils_1 = require("../prompt/path-utils");
async function createPromptEditCommand() {
    const { Command } = await import("commander");
    const command = new Command("edit");
    command
        .description("Materialize the active prompt into the user layer and open it when an editor is configured.")
        .requiredOption("--prompt <path>", "Repository-relative prompt path to edit.")
        .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 repositoryContext = (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false);
        const configResult = (0, config_store_1.readResolvedConfig)(repositoryContext);
        const commandOptions = commandInstance.opts();
        const requestedPromptPath = (0, paths_1.parseRepositoryRelativePath)(readRequiredStringOption(commandOptions.prompt, "--prompt")).normalizedPath;
        const promptResolution = (0, config_layer_resolution_1.resolveRequiredPromptReference)({
            repositoryRoot: repositoryContext.root,
            config: configResult.resolved.values,
            requestedPromptPath
        });
        const destinationPromptPath = (0, path_utils_1.toUserLayerPromptPath)(requestedPromptPath, configResult.resolved.values);
        const destinationAbsolutePath = (0, config_contract_1.resolveRepositoryRelativePath)(repositoryContext.root, destinationPromptPath);
        const sourceAbsolutePath = (0, path_utils_1.resolvePromptSourceAbsolutePath)({
            repositoryRoot: repositoryContext.root,
            resolvedPromptPath: promptResolution.resolvedPromptPath,
            config: configResult.resolved.values,
            source: promptResolution.source
        });
        const sourceContent = node_fs_1.default.readFileSync(sourceAbsolutePath, "utf8");
        let copyApplied = false;
        let preservedExistingUserPrompt = false;
        let writeOutcome = "keep";
        let recoveryGuidance = [];
        if (promptResolution.resolvedLayer !== "user") {
            if (node_fs_1.default.existsSync(destinationAbsolutePath)) {
                preservedExistingUserPrompt = true;
                recoveryGuidance = [
                    "Compare the existing user prompt with the active source before replacing it.",
                    "Use prompt init --force only when replacing the user-layer prompt is intended.",
                    "Use repository history or backups to recover prior prompt content."
                ];
            }
            else {
                applyPromptMaterialization({
                    repositoryRoot: repositoryContext.root,
                    destinationPromptPath,
                    sourcePromptPath: promptResolution.resolvedPromptPath,
                    sourceLayer: requireUpstreamLayer(promptResolution.resolvedLayer),
                    sourceContent
                });
                copyApplied = true;
                writeOutcome = "create";
            }
        }
        const editorCommand = normalizeEditorCommand(configResult.resolved.values.editor);
        const opened = maybeLaunchEditor({
            editorCommand,
            destinationAbsolutePath
        });
        const result = {
            requestedPromptPath,
            resolvedPromptPath: promptResolution.resolvedPromptPath,
            destinationPromptPath,
            resolvedLayer: promptResolution.resolvedLayer,
            source: promptResolution.source,
            activeSource: {
                requestedPromptPath,
                resolvedPromptPath: promptResolution.resolvedPromptPath,
                resolvedLayer: promptResolution.resolvedLayer,
                sourceFamily: promptResolution.source,
                destinationPromptPath
            },
            fallbackTrace: promptResolution.fallbackTrace,
            writeOutcome,
            copyApplied,
            preservedExistingUserPrompt,
            recoveryGuidance,
            opened,
            editorConfigured: editorCommand !== null,
            warning: promptResolution.warning,
            promptRenderingEvidence: (0, prompt_rendering_evidence_1.collectPromptRenderingEvidence)({
                repositoryRoot: repositoryContext.root,
                requestedPromptPath,
                resolvedPromptPath: promptResolution.resolvedPromptPath,
                resolvedLayer: promptResolution.resolvedLayer,
                sourceFamily: promptResolution.source,
                fallbackTrace: promptResolution.fallbackTrace,
                userLayerDestinationPath: destinationPromptPath,
                promptResolutionWarning: promptResolution.warning,
                promptInstructionsPath: promptResolution.resolvedPromptPath,
                requireAgentEntrypoint: false,
                degradedNoAgent: false
            }),
            promptVersionEvidence: (0, prompt_version_evidence_1.collectPromptVersionEvidence)({
                repositoryRoot: repositoryContext.root,
                promptPath: promptResolution.resolvedPromptPath,
                promptContent: sourceContent,
                manifestPath: node_path_1.default.posix.join(configResult.resolved.values.prompt_user_root, "manifest.json"),
                canonicalPromptPath: destinationPromptPath
            })
        };
        (0, output_1.emitSuccess)({
            command: "prompt edit",
            format,
            text: renderPromptEditText(result),
            data: {
                repositoryRoot: repositoryContext.root,
                detectionSource: repositoryContext.detectionSource,
                requestedPromptPath: result.requestedPromptPath,
                resolvedPromptPath: result.resolvedPromptPath,
                destinationPromptPath: result.destinationPromptPath,
                activeSource: result.activeSource,
                fallbackTrace: result.fallbackTrace,
                promptResolution,
                promptRenderingEvidence: result.promptRenderingEvidence,
                promptVersionEvidence: result.promptVersionEvidence,
                writeOutcome: result.writeOutcome,
                copyApplied: result.copyApplied,
                preservedExistingUserPrompt: result.preservedExistingUserPrompt,
                recoveryGuidance: result.recoveryGuidance,
                opened: result.opened,
                editorConfigured: result.editorConfigured
            }
        });
    });
    return command;
}
function readRequiredStringOption(value, flagName) {
    if (typeof value !== "string" || value.trim().length === 0) {
        throw (0, errors_1.createUsageError)(`${flagName} requires a non-empty value.`, [
            `Pass ${flagName} with a repository-relative prompt path.`
        ]);
    }
    return value;
}
function applyPromptMaterialization(options) {
    const mutation = (0, prompt_materialization_1.createPromptMaterializationMutation)({
        repositoryRoot: options.repositoryRoot,
        promptPath: options.destinationPromptPath,
        promptContents: options.sourceContent,
        upstreamPath: options.sourcePromptPath,
        upstreamLayer: options.sourceLayer,
        upstreamContents: options.sourceContent,
        writeOwner: "prompt edit"
    });
    (0, prompt_materialization_1.applyPromptMaterializationMutationSync)({
        repositoryRoot: options.repositoryRoot,
        mutation
    });
}
function requireUpstreamLayer(layer) {
    if (layer === "latest" || layer === "packaged-default") {
        return layer;
    }
    throw new Error("Prompt materialization cannot use the user layer as its upstream base.");
}
function normalizeEditorCommand(editor) {
    if (editor === undefined) {
        return null;
    }
    const trimmed = editor.trim();
    return trimmed.length > 0 ? trimmed : null;
}
function maybeLaunchEditor(options) {
    if (options.editorCommand === null) {
        return false;
    }
    const result = (0, node_child_process_1.spawnSync)(buildShellEditorCommand(options.editorCommand, options.destinationAbsolutePath), {
        shell: true,
        stdio: "inherit"
    });
    if (result.error) {
        throw (0, errors_1.createInvalidConfigError)("Prompt edit could not launch the configured editor.", [
            `Editor command: ${options.editorCommand}`,
            result.error.message
        ]);
    }
    if (result.status !== 0) {
        throw (0, errors_1.createInvalidConfigError)("Prompt edit could not launch the configured editor.", [
            `Editor command: ${options.editorCommand}`,
            `Exit status: ${String(result.status)}`
        ]);
    }
    return true;
}
function buildShellEditorCommand(editorCommand, destinationAbsolutePath) {
    return `${editorCommand} ${quoteShellArgument(destinationAbsolutePath)}`;
}
function quoteShellArgument(value) {
    if (process.platform === "win32") {
        return `"${value.replace(/(["%])/g, "^$1")}"`;
    }
    return `'${value.replace(/'/g, "'\\''")}'`;
}
function renderPromptEditText(result) {
    const lines = [
        (0, output_1.renderTerminalHeading)("Prompt Edit", "title"),
        (0, output_1.renderTerminalSection)({
            heading: "Summary",
            fields: [
                { label: "Write outcome", value: result.writeOutcome },
                { label: "Copy applied", value: result.copyApplied ? "yes" : "no" },
                { label: "Preserved existing user prompt", value: result.preservedExistingUserPrompt ? "yes" : "no" },
                { label: "Editor configured", value: result.editorConfigured ? "yes" : "no" },
                { label: "Opened editor", value: result.opened ? "yes" : "no" }
            ]
        }),
        "",
        (0, output_1.renderTerminalSection)({
            heading: "Paths",
            fields: [
                { label: "Requested prompt", value: result.requestedPromptPath },
                { label: "Resolved prompt", value: result.resolvedPromptPath },
                { label: "Destination", value: result.destinationPromptPath }
            ]
        }),
        "",
        (0, output_1.renderTerminalSection)({
            heading: "Prompt Source",
            fields: [
                { label: "Resolved layer", value: `${result.resolvedLayer} (${result.source})` },
                {
                    label: "Active source",
                    value: `${result.activeSource.resolvedPromptPath} [${result.activeSource.resolvedLayer}/${result.activeSource.sourceFamily}]`
                },
                { label: "Fallback trace", value: result.fallbackTrace.length === 0 ? "(none)" : result.fallbackTrace.join("\n") }
            ]
        }),
        "",
        (0, output_1.renderTerminalSection)({
            heading: "Write Boundary",
            lines: [
                result.copyApplied
                    ? (0, output_1.renderTerminalBoundary)({
                        kind: "write-applied",
                        target: result.destinationPromptPath,
                        targetLabel: "Destination"
                    })
                    : result.preservedExistingUserPrompt
                        ? (0, output_1.renderTerminalBoundary)({
                            kind: "force-gated-write",
                            reason: "Existing user-layer prompt was preserved; use prompt init --force only when replacement is intended."
                        })
                        : (0, output_1.renderTerminalBoundary)({
                            kind: "mutating-no-op",
                            reason: "User-layer prompt already exists for editing.",
                            target: result.destinationPromptPath,
                            targetLabel: "Destination"
                        })
            ]
        })
    ];
    if (result.recoveryGuidance.length > 0) {
        lines.push("", (0, output_1.renderTerminalCompactList)({
            heading: "Recovery",
            entries: result.recoveryGuidance.map((guidance) => ({ label: guidance }))
        }));
    }
    if (result.warning !== null) {
        lines.push("", (0, output_1.renderTerminalSection)({
            heading: "Warnings",
            lines: [result.warning]
        }));
    }
    lines.push("", (0, output_1.renderTerminalSection)({
        heading: "Prompt Rendering Evidence",
        fields: [
            { label: "Prompt render lanes", value: result.promptRenderingEvidence.visibleLaneOrder.join(" -> ") },
            {
                label: "Agent entrypoint",
                value: `${result.promptRenderingEvidence.agentEntrypointGuidance.path} (${result.promptRenderingEvidence.agentEntrypointGuidance.present ? "present" : "missing"})`
            },
            {
                label: "Agent entrypoint required for this surface",
                value: result.promptRenderingEvidence.agentEntrypointGuidance.requiredForSurface ? "yes" : "no"
            },
            {
                label: "Degraded mode",
                value: result.promptRenderingEvidence.degradedMode.requested ? result.promptRenderingEvidence.degradedMode.explicitFlag : "no"
            },
            { label: "Unresolved token pattern", value: result.promptRenderingEvidence.unresolvedTokenPattern }
        ]
    }), "", (0, output_1.renderTerminalSection)({
        heading: "Version Evidence",
        fields: [
            { label: "Prompt Markdown version", value: renderEvidenceValue(result.promptVersionEvidence.promptMarkdown.promptVersion) },
            { label: "Prompt manifest version", value: renderEvidenceValue(result.promptVersionEvidence.promptManifest.promptManifestVersion) },
            { label: "Prompt manifest baseline prompt_version", value: renderEvidenceValue(result.promptVersionEvidence.promptManifest.promptVersion) },
            {
                label: `Prompt manifest entry version (${result.promptVersionEvidence.promptManifest.entryPath})`,
                value: renderEvidenceValue(result.promptVersionEvidence.promptManifest.entryVersion)
            }
        ]
    }));
    if (result.promptVersionEvidence.promptManifest.warning !== null) {
        lines.push("", (0, output_1.renderTerminalSection)({
            heading: "Manifest Warnings",
            lines: [result.promptVersionEvidence.promptManifest.warning]
        }));
    }
    if (!result.editorConfigured) {
        lines.push("", (0, output_1.renderTerminalSection)({
            heading: "Next Action",
            lines: [
                (0, output_1.renderTerminalNextAction)({
                    command: `Edit ${result.destinationPromptPath} manually or configure the editor setting.`
                })
            ]
        }));
    }
    return `${lines.join("\n")}\n`;
}
function renderEvidenceValue(value) {
    return value === null ? "(missing)" : String(value);
}
