"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.executeMetadataUpdateOperation = executeMetadataUpdateOperation;
exports.executeOverviewUpdateOperation = executeOverviewUpdateOperation;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const config_contract_1 = require("../../lib/config/config-contract");
const cli_constants_1 = require("../../lib/config/cli-constants");
const errors_1 = require("../../lib/errors");
const lifecycle_metadata_posture_1 = require("../../lib/lifecycle-metadata-posture");
const output_1 = require("../../lib/output");
const paths_1 = require("../../lib/paths");
const prompt_version_evidence_1 = require("../../lib/prompts/prompt-version-evidence");
const front_matter_utils_1 = require("../../lib/planning/front-matter-utils");
const runtime_acceptance_1 = require("../../lib/planning/runtime-acceptance");
const global_format_1 = require("./global-format");
const update_application_1 = require("./metadata/update-application");
const update_reporting_1 = require("./metadata/update-reporting");
const persisted_artifact_reminder_1 = require("./persisted-artifact-reminder");
function normalizeOptionalRepositoryRelativeOption(input, optionName) {
    if (input === undefined || input === null || input === '') {
        return null;
    }
    if (typeof input !== 'string') {
        throw (0, errors_1.createUsageError)(`${optionName} must be a repository-relative path.`, [`Received: ${String(input)}`]);
    }
    try {
        return (0, paths_1.parseRepositoryRelativePath)(input).normalizedPath;
    }
    catch (error) {
        if (error instanceof RangeError) {
            throw (0, errors_1.createUsageError)(`${optionName} must be a repository-relative path.`, [error.message]);
        }
        throw error;
    }
}
function assertActiveArtifactMatchesSelection(options) {
    if (options.activeArtifactPath === null || options.activeArtifactPath === options.artifactPath) {
        return;
    }
    throw new TypeError([
        `Active artifact conflict for ${options.commandName}.`,
        'Evidence source: --active-artifact and selected command artifact argument.',
        `Field '--active-artifact' is '${options.activeArtifactPath}'; expected '${options.artifactPath}'.`,
        'Recovery: rerun the command with matching --active-artifact and selected artifact paths, or omit --active-artifact when no explicit handoff is being checked. No partial write was applied.',
    ].join(' '));
}
function executeMetadataUpdateOperation(options) {
    const format = (0, output_1.resolveOutputFormat)((0, global_format_1.getGlobalFormat)(options.commandInstance));
    if (format === null) {
        throw (0, errors_1.createUsageError)('Output format must be one of: text, json.', [
            `Received: ${String((0, global_format_1.getGlobalFormat)(options.commandInstance))}`,
        ]);
    }
    const commandOptions = options.commandInstance.opts();
    const artifactPathOption = options.artifactPathOption ?? 'artifact';
    const artifactPathOptionFlag = artifactPathOption.replace(/([A-Z])/g, '-$1').toLowerCase();
    const artifactPathInput = options.artifactPathOverride ??
        (0, update_application_1.readRequiredStringOption)(commandOptions[artifactPathOption], `--${artifactPathOptionFlag}`);
    const assignments = (0, update_application_1.parseFieldAssignments)(options.fieldAssignmentsOverride !== undefined
        ? Array.from(options.fieldAssignmentsOverride)
        : commandOptions.field);
    const parsedArtifact = (0, paths_1.parseRepositoryRelativePath)(artifactPathInput);
    const artifactPath = parsedArtifact.normalizedPath;
    const activeArtifactPath = normalizeOptionalRepositoryRelativeOption(commandOptions.activeArtifact, '--active-artifact');
    const runDirectoryPath = normalizeOptionalRepositoryRelativeOption(commandOptions.runDirectory, '--run-directory');
    const absolutePath = (0, paths_1.resolveRepositoryRelativePath)(options.repositoryRoot, parsedArtifact);
    if (!node_fs_1.default.existsSync(absolutePath)) {
        throw (0, errors_1.createUsageError)(`Artifact path '${artifactPath}' does not exist.`, [
            'Pass an existing repository-relative --artifact path.',
        ]);
    }
    const originalContent = node_fs_1.default.readFileSync(absolutePath, 'utf8');
    let detectedFamily = (0, update_reporting_1.detectMetadataFamilyForReporting)(artifactPath, originalContent);
    let lifecycleMetadataPosture = null;
    try {
        assertActiveArtifactMatchesSelection({
            artifactPath,
            activeArtifactPath,
            commandName: options.commandName,
        });
        const family = (0, update_application_1.detectMetadataFamily)(artifactPath, originalContent);
        detectedFamily = family;
        if (options.expectedFamilies !== undefined && !options.expectedFamilies.includes(family)) {
            throw (0, errors_1.createUsageError)(`Artifact '${artifactPath}' is not supported by ${options.commandName}.`, [
                `Expected metadata family: ${options.expectedFamilies.join(', ')}.`,
                `Detected metadata family: ${family}.`,
            ]);
        }
        if (family === 'planning-artifact') {
            const artifactType = (0, update_application_1.readFrontMatter)(artifactPath, originalContent).artifactType;
            (0, update_application_1.assertNoPairOwnedLifecycleAssignments)({
                artifactType,
                assignments,
            });
            lifecycleMetadataPosture = options.write
                ? (0, lifecycle_metadata_posture_1.enforceLifecycleMetadataPosture)({
                    repositoryRoot: options.repositoryRoot,
                    runDirectory: runDirectoryPath,
                    artifactPath,
                    artifactType: artifactType ?? '',
                    assignments: (0, update_application_1.toFieldChanges)(assignments),
                })
                : null;
        }
        const nextContent = (0, update_application_1.applyFamilyAwareUpdates)({
            family,
            artifactPath,
            originalContent,
            repositoryRoot: options.repositoryRoot,
            assignments,
        });
        const changed = nextContent !== originalContent;
        if (options.write && changed) {
            if (options.persistContent === undefined) {
                node_fs_1.default.writeFileSync(absolutePath, nextContent, 'utf8');
            }
            else {
                options.persistContent({
                    artifactPath,
                    absolutePath,
                    family,
                    originalContent,
                    nextContent,
                });
            }
        }
        const result = {
            artifactPath,
            activeArtifactPath,
            runDirectoryPath,
            lifecycleMetadataPosture,
            family,
            changed,
            writeApplied: options.write && changed,
            fieldChanges: (0, update_application_1.toFieldChanges)(assignments),
            reportingAlignment: (0, update_reporting_1.createMetadataReportingAlignment)({
                family,
                writeRequested: options.write,
            }),
            commandWriteSummary: (0, update_reporting_1.createMetadataCommandWriteSummary)({
                artifactPath,
                changed,
                writeApplied: options.write && changed,
                writeRequested: options.write,
                jsonOnly: format === 'json',
            }),
            promptVersionEvidence: family === 'prompt'
                ? (0, prompt_version_evidence_1.collectPromptVersionEvidence)({
                    repositoryRoot: options.repositoryRoot,
                    promptPath: artifactPath,
                    promptContent: nextContent,
                    manifestPath: node_path_1.default.posix.join(config_contract_1.BUILT_IN_CONFIG_DEFAULTS.prompt_user_root, 'manifest.json'),
                    canonicalPromptPath: artifactPath,
                })
                : undefined,
        };
        const persistedArtifactLicenseReminder = (0, persisted_artifact_reminder_1.applyPlanningCommandPersistedArtifactReminderWrites)({
            repositoryContext: {
                root: options.repositoryRoot,
                detectionSource: options.detectionSource,
            },
            commandWriteSummary: result.commandWriteSummary,
            format,
        });
        (0, output_1.emitSuccess)({
            command: options.commandName,
            format,
            text: (0, update_reporting_1.renderMetadataOperationText)(result, options.write),
            data: {
                repositoryRoot: options.repositoryRoot,
                detectionSource: options.detectionSource,
                artifactPath,
                activeArtifactPath,
                runDirectory: runDirectoryPath,
                runDirectoryPath,
                lifecycleMetadataPosture: result.lifecycleMetadataPosture,
                family,
                requestedFieldCount: assignments.length,
                fieldChanges: result.fieldChanges,
                changed,
                writeApplied: result.writeApplied,
                commandWriteSummary: persistedArtifactLicenseReminder.commandWriteSummary,
                persistedArtifactLicenseReminder,
                reportingAlignment: result.reportingAlignment,
                promptVersionEvidence: result.promptVersionEvidence,
            },
        });
    }
    catch (error) {
        if (error instanceof TypeError || error instanceof RangeError || error instanceof SyntaxError) {
            throw (0, errors_1.createBlockingInvalidConfigError)({
                message: 'Metadata updates were rejected.',
                detail: error.message,
                findingCode: 'METADATA_UPDATE_BLOCKED',
                path: artifactPath,
                blockingReason: 'invalid-command-input',
                recovery: 'Correct the rejected metadata field request or artifact metadata, then rerun the command. No partial write was applied.',
                evidenceDetails: (0, update_reporting_1.createMetadataRejectionEvidence)({
                    commandName: options.commandName,
                    artifactPath,
                    family: detectedFamily,
                    assignments,
                    rejectionDetail: error.message,
                }),
            });
        }
        throw error;
    }
}
function executeOverviewUpdateOperation(options) {
    const format = (0, output_1.resolveOutputFormat)((0, global_format_1.getGlobalFormat)(options.commandInstance));
    if (format === null) {
        throw (0, errors_1.createUsageError)('Output format must be one of: text, json.', [
            `Received: ${String((0, global_format_1.getGlobalFormat)(options.commandInstance))}`,
        ]);
    }
    const commandOptions = options.commandInstance.opts();
    const dashOption = options.artifactPathOption.replace(/([A-Z])/g, '-$1').toLowerCase();
    const artifactPathInput = (0, update_application_1.readRequiredStringOption)(commandOptions[options.artifactPathOption], `--${dashOption}`);
    const assignments = (0, update_application_1.parseFieldAssignments)(commandOptions.field);
    const parsedArtifact = (0, paths_1.parseRepositoryRelativePath)(artifactPathInput);
    const artifactPath = parsedArtifact.normalizedPath;
    const activeArtifactPath = normalizeOptionalRepositoryRelativeOption(commandOptions.activeArtifact, '--active-artifact');
    const runDirectoryPath = normalizeOptionalRepositoryRelativeOption(commandOptions.runDirectory, '--run-directory');
    const absolutePath = (0, paths_1.resolveRepositoryRelativePath)(options.repositoryRoot, parsedArtifact);
    if (!node_fs_1.default.existsSync(absolutePath)) {
        throw (0, errors_1.createUsageError)(`Artifact path '${artifactPath}' does not exist.`, [
            `Pass an existing repository-relative --${dashOption} path.`,
        ]);
    }
    const originalContent = node_fs_1.default.readFileSync(absolutePath, 'utf8');
    let detectedFamily = 'planning-artifact';
    try {
        assertActiveArtifactMatchesSelection({
            artifactPath,
            activeArtifactPath,
            commandName: options.commandName,
        });
        const frontMatter = (0, update_application_1.readFrontMatter)(artifactPath, originalContent);
        if (frontMatter.artifactType?.trim() !== options.expectedArtifactType) {
            throw (0, errors_1.createUsageError)(`Artifact '${artifactPath}' is not a ${options.expectedArtifactType} artifact.`, [
                `Expected artifact_type '${options.expectedArtifactType}', found '${frontMatter.artifactType ?? '(none)'}'.`,
                `Pass a repository-relative path to an existing ${options.expectedArtifactType.replace(/_/g, ' ')} file.`,
            ]);
        }
        (0, update_application_1.assertNoPairOwnedLifecycleAssignments)({
            artifactType: frontMatter.artifactType,
            assignments,
        });
        const lifecycleMetadataPosture = options.write
            ? (0, lifecycle_metadata_posture_1.enforceLifecycleMetadataPosture)({
                repositoryRoot: options.repositoryRoot,
                runDirectory: runDirectoryPath,
                artifactPath,
                artifactType: frontMatter.artifactType ?? '',
                assignments: (0, update_application_1.toFieldChanges)(assignments),
            })
            : null;
        const updates = (0, update_application_1.toStringUpdateMap)(assignments);
        const transitionUpdates = {};
        const frontMatterUpdates = {};
        for (const [key, value] of Object.entries(updates)) {
            if (cli_constants_1.CLI_METADATA_STATUS_AND_PLANNING_FIELDS.has(key)) {
                transitionUpdates[key] = value;
            }
            else {
                frontMatterUpdates[key] = value;
            }
        }
        let nextContent = originalContent;
        const runtimeAcceptanceUpdate = options.expectedArtifactType === 'task_definition'
            ? frontMatterUpdates.runtime_acceptance
            : undefined;
        if (runtimeAcceptanceUpdate !== undefined) {
            delete frontMatterUpdates.runtime_acceptance;
        }
        if (Object.keys(transitionUpdates).length > 0) {
            nextContent = (0, front_matter_utils_1.applyStatusAndPlanningFieldTransition)(nextContent, transitionUpdates);
        }
        if (Object.keys(frontMatterUpdates).length > 0) {
            nextContent = (0, front_matter_utils_1.applyPlanningFrontMatterFieldUpdates)(nextContent, frontMatterUpdates, {
                repositoryRelativePathKeys: cli_constants_1.CLI_REPOSITORY_RELATIVE_PARENT_LINK_KEYS,
            });
        }
        if (runtimeAcceptanceUpdate !== undefined) {
            nextContent = (0, runtime_acceptance_1.applyTaskRuntimeAcceptanceFieldUpdate)(nextContent, runtimeAcceptanceUpdate);
        }
        (0, update_application_1.assertPlanningArtifactSelectionIsConsistent)({
            repositoryRoot: options.repositoryRoot,
            artifactPath,
            content: nextContent,
        });
        const changed = nextContent !== originalContent;
        if (options.write && changed) {
            node_fs_1.default.writeFileSync(absolutePath, nextContent, 'utf8');
        }
        const result = {
            artifactPath,
            activeArtifactPath,
            runDirectoryPath,
            lifecycleMetadataPosture,
            family: 'planning-artifact',
            changed,
            writeApplied: options.write && changed,
            fieldChanges: (0, update_application_1.toFieldChanges)(assignments),
            reportingAlignment: (0, update_reporting_1.createMetadataReportingAlignment)({
                family: 'planning-artifact',
                writeRequested: options.write,
            }),
            commandWriteSummary: (0, update_reporting_1.createMetadataCommandWriteSummary)({
                artifactPath,
                changed,
                writeApplied: options.write && changed,
                writeRequested: options.write,
                jsonOnly: format === 'json',
            }),
        };
        const persistedArtifactLicenseReminder = (0, persisted_artifact_reminder_1.applyPlanningCommandPersistedArtifactReminderWrites)({
            repositoryContext: {
                root: options.repositoryRoot,
                detectionSource: options.detectionSource,
            },
            commandWriteSummary: result.commandWriteSummary,
            format,
        });
        (0, output_1.emitSuccess)({
            command: options.commandName,
            format,
            text: (0, update_reporting_1.renderMetadataOperationText)(result, options.write),
            data: {
                repositoryRoot: options.repositoryRoot,
                detectionSource: options.detectionSource,
                artifactPath,
                activeArtifactPath,
                runDirectory: runDirectoryPath,
                runDirectoryPath,
                lifecycleMetadataPosture: result.lifecycleMetadataPosture,
                family: 'planning-artifact',
                requestedFieldCount: assignments.length,
                fieldChanges: result.fieldChanges,
                changed,
                writeApplied: result.writeApplied,
                commandWriteSummary: persistedArtifactLicenseReminder.commandWriteSummary,
                persistedArtifactLicenseReminder,
                reportingAlignment: result.reportingAlignment,
            },
        });
    }
    catch (error) {
        if (error instanceof TypeError || error instanceof RangeError || error instanceof SyntaxError) {
            throw (0, errors_1.createBlockingInvalidConfigError)({
                message: 'Metadata updates were rejected.',
                detail: error.message,
                findingCode: 'METADATA_UPDATE_BLOCKED',
                path: artifactPath,
                blockingReason: 'invalid-command-input',
                recovery: 'Correct the rejected metadata field request or artifact metadata, then rerun the command. No partial write was applied.',
                evidenceDetails: (0, update_reporting_1.createMetadataRejectionEvidence)({
                    commandName: options.commandName,
                    artifactPath,
                    family: detectedFamily,
                    assignments,
                    rejectionDetail: error.message,
                }),
            });
        }
        throw error;
    }
}
