"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.promoteTaskWorkspace = promoteTaskWorkspace;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../errors");
const paths_1 = require("../paths");
const front_matter_utils_1 = require("./front-matter-utils");
function promoteTaskWorkspace(repositoryRoot, options) {
    const sourceTaskDefinitionPath = resolveSourceTaskDefinitionPath(repositoryRoot, options.sourceTaskDefinitionPath);
    if (!node_fs_1.default.existsSync(sourceTaskDefinitionPath.absolute)) {
        throw (0, errors_1.createUsageError)(`Source task definition not found at '${sourceTaskDefinitionPath.relative}'.`, ["Pass an existing repository-relative --task-definition path."]);
    }
    const sourceTaskDirectoryPath = node_path_1.default.dirname(sourceTaskDefinitionPath.absolute);
    const sourceImplementationSummaryPath = node_path_1.default.join(sourceTaskDirectoryPath, "implementation-summary.md");
    if (!node_fs_1.default.existsSync(sourceImplementationSummaryPath)) {
        throw (0, errors_1.createUsageError)(`Source implementation summary not found at '${(0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, sourceImplementationSummaryPath))}'.`, ["Promotion requires both task-definition.md and implementation-summary.md in the source task directory."]);
    }
    const taskDefinitionText = node_fs_1.default.readFileSync(sourceTaskDefinitionPath.absolute, "utf8");
    const parsedTaskDefinition = parseTaskDefinitionFrontMatter(sourceTaskDefinitionPath.relative, taskDefinitionText);
    const destinationTaskDirectoryPath = node_path_1.default.join(repositoryRoot, node_path_1.default.dirname(parsedTaskDefinition.milestoneOverviewPath), "tasks", parsedTaskDefinition.taskSlug);
    if ((0, paths_1.pathsEqualForFilesystem)(sourceTaskDirectoryPath, destinationTaskDirectoryPath)) {
        throw (0, errors_1.createUsageError)("Task is already in the canonical milestone tasks location.", [
            `Task definition: ${sourceTaskDefinitionPath.relative}`,
            `Canonical destination: ${(0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, destinationTaskDirectoryPath))}`
        ]);
    }
    if (node_fs_1.default.existsSync(destinationTaskDirectoryPath)) {
        throw (0, errors_1.createUsageError)("Promotion would create duplicate active task locations.", [
            `Source directory: ${(0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, sourceTaskDirectoryPath))}`,
            `Canonical destination already exists: ${(0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, destinationTaskDirectoryPath))}`
        ]);
    }
    const destinationTaskDefinitionPath = node_path_1.default.join(destinationTaskDirectoryPath, "task-definition.md");
    const destinationTaskDefinitionPathRelative = (0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, destinationTaskDefinitionPath));
    const destinationImplementationSummaryPath = node_path_1.default.join(destinationTaskDirectoryPath, "implementation-summary.md");
    const destinationImplementationSummaryPathRelative = (0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, destinationImplementationSummaryPath));
    const implementationSummaryText = node_fs_1.default.readFileSync(sourceImplementationSummaryPath, "utf8");
    const summaryUpdate = updateUpstreamTaskDefinitionPath((0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, sourceImplementationSummaryPath)), implementationSummaryText, destinationTaskDefinitionPathRelative);
    if (!options.dryRun) {
        node_fs_1.default.mkdirSync(node_path_1.default.dirname(destinationTaskDirectoryPath), { recursive: true });
        node_fs_1.default.renameSync(sourceTaskDirectoryPath, destinationTaskDirectoryPath);
        if (summaryUpdate.changed) {
            node_fs_1.default.writeFileSync(destinationImplementationSummaryPath, summaryUpdate.updatedContent, "utf8");
        }
    }
    return {
        repositoryRoot,
        dryRun: options.dryRun,
        taskSlug: parsedTaskDefinition.taskSlug,
        sourceTaskDefinitionPath: sourceTaskDefinitionPath.relative,
        sourceTaskDirectoryPath,
        destinationTaskDefinitionPath: destinationTaskDefinitionPathRelative,
        destinationTaskDirectoryPath,
        destinationImplementationSummaryPath: destinationImplementationSummaryPathRelative,
        taskDirectoryAction: options.dryRun ? "kept" : "moved",
        sourceDirectoryAction: options.dryRun ? "kept" : "removed",
        frontMatterChanges: summaryUpdate.changed
            ? [
                {
                    filePath: summaryUpdate.filePath,
                    field: "upstream.task_definition",
                    before: summaryUpdate.before,
                    after: summaryUpdate.after
                }
            ]
            : []
    };
}
function resolveSourceTaskDefinitionPath(repositoryRoot, inputPath) {
    try {
        const parsed = (0, paths_1.parseRepositoryRelativePath)(inputPath);
        if (parsed.segments[parsed.segments.length - 1] !== "task-definition.md") {
            throw (0, errors_1.createUsageError)(`Invalid --task-definition path '${inputPath}'.`, ["Expected a repository-relative path ending in task-definition.md."]);
        }
        return {
            relative: parsed.normalizedPath,
            absolute: node_path_1.default.join(repositoryRoot, parsed.normalizedPath)
        };
    }
    catch (error) {
        if (error instanceof Error && error.name === "RuntimeError") {
            throw error;
        }
        throw (0, errors_1.createUsageError)(`Invalid --task-definition path '${inputPath}'.`, [error instanceof Error ? error.message : String(error)]);
    }
}
function parseTaskDefinitionFrontMatter(filePath, fileText) {
    const frontMatter = extractFrontMatter(filePath, fileText);
    const taskSlug = readTopLevelField(frontMatter.lines, "task");
    if (taskSlug === undefined || taskSlug.trim() === "") {
        throw (0, errors_1.createUsageError)(`Task definition '${filePath}' is missing required top-level field 'task'.`);
    }
    const resolvedTaskSlug = resolveTaskSlug(taskSlug.trim());
    const milestoneOverviewPath = readUpstreamField(frontMatter.lines, "milestone_overview");
    if (milestoneOverviewPath === undefined || milestoneOverviewPath.trim() === "") {
        throw (0, errors_1.createUsageError)(`Task definition '${filePath}' is missing required upstream field 'milestone_overview'.`);
    }
    const normalizedMilestoneOverviewPath = (0, paths_1.parseRepositoryRelativePath)(milestoneOverviewPath.trim()).normalizedPath;
    if (!isMilestoneOverviewPath(normalizedMilestoneOverviewPath)) {
        throw (0, errors_1.createUsageError)(`Task definition '${filePath}' has invalid upstream.milestone_overview '${milestoneOverviewPath.trim()}'.`, [
            `Expected a repository-relative path ending in ${(0, paths_1.getCanonicalPlanningOverviewFilename)("milestone")} or supported legacy ${paths_1.LEGACY_PLANNING_OVERVIEW_FILENAME}.`
        ]);
    }
    return {
        taskSlug: resolvedTaskSlug,
        milestoneOverviewPath: normalizedMilestoneOverviewPath
    };
}
function isMilestoneOverviewPath(pathValue) {
    return pathValue.endsWith(`/${(0, paths_1.getCanonicalPlanningOverviewFilename)("milestone")}`)
        || pathValue.endsWith(`/${paths_1.LEGACY_PLANNING_OVERVIEW_FILENAME}`);
}
function updateUpstreamTaskDefinitionPath(filePath, content, nextTaskDefinitionPath) {
    const frontMatter = extractFrontMatter(filePath, content);
    const currentTaskDefinitionPath = readUpstreamField(frontMatter.lines, "task_definition");
    if (currentTaskDefinitionPath === undefined || currentTaskDefinitionPath.trim() === "") {
        throw (0, errors_1.createInvalidConfigError)(`Implementation summary '${filePath}' is missing required upstream field 'task_definition'.`, [], [
            {
                code: "TASK_PROMOTION_METADATA_INVALID",
                message: "Missing required upstream.task_definition in implementation summary front matter.",
                severity: "error",
                path: filePath
            }
        ]);
    }
    let normalizedCurrentPath;
    try {
        normalizedCurrentPath = (0, paths_1.parseRepositoryRelativePath)(currentTaskDefinitionPath.trim()).normalizedPath;
    }
    catch (error) {
        throw (0, errors_1.createInvalidConfigError)(`Implementation summary '${filePath}' has invalid upstream.task_definition '${currentTaskDefinitionPath.trim()}'.`, ["Expected a repository-relative path."], [
            {
                code: "TASK_PROMOTION_METADATA_INVALID",
                message: "Invalid upstream.task_definition path in implementation summary metadata.",
                severity: "error",
                path: filePath
            }
        ]);
    }
    if (normalizedCurrentPath === nextTaskDefinitionPath) {
        return {
            changed: false,
            before: normalizedCurrentPath,
            after: nextTaskDefinitionPath,
            updatedContent: content,
            filePath
        };
    }
    const transitionUpdates = buildImplementationSummaryTransitionUpdates(filePath, frontMatter.lines);
    let transitionAppliedContent;
    try {
        transitionAppliedContent = (0, front_matter_utils_1.applyStatusAndPlanningFieldTransition)(content, transitionUpdates);
    }
    catch (error) {
        throw (0, errors_1.createInvalidConfigError)(`Implementation summary '${filePath}' could not apply required status/planning transition update.`, [error instanceof Error ? error.message : String(error)], [
            {
                code: "TASK_PROMOTION_METADATA_UPDATE_BLOCKED",
                message: error instanceof Error ? error.message : String(error),
                severity: "error",
                path: filePath
            }
        ]);
    }
    let updatedContent;
    try {
        updatedContent = (0, front_matter_utils_1.applyPlanningFrontMatterFieldUpdates)(transitionAppliedContent, {
            "upstream.task_definition": nextTaskDefinitionPath
        }, {
            requiredKeys: ["upstream.task_definition"],
            repositoryRelativePathKeys: ["upstream.task_definition"]
        });
    }
    catch (error) {
        throw (0, errors_1.createInvalidConfigError)(`Implementation summary '${filePath}' could not apply required upstream.task_definition update.`, [error instanceof Error ? error.message : String(error)], [
            {
                code: "TASK_PROMOTION_METADATA_UPDATE_BLOCKED",
                message: error instanceof Error ? error.message : String(error),
                severity: "error",
                path: filePath
            }
        ]);
    }
    return {
        changed: true,
        before: normalizedCurrentPath,
        after: nextTaskDefinitionPath,
        updatedContent,
        filePath
    };
}
function buildImplementationSummaryTransitionUpdates(filePath, lines) {
    const updates = {};
    for (const key of [
        "slice",
        "phase",
        "milestone",
        "task",
        "planning_depth",
        "status",
        "implementation_status"
    ]) {
        const value = readTopLevelField(lines, key);
        if (value === undefined || value.trim() === "") {
            throw (0, errors_1.createUsageError)(`Implementation summary '${filePath}' is missing required top-level field '${key}'.`);
        }
        updates[key] = value.trim();
    }
    return updates;
}
function resolveTaskSlug(rawTaskSlug) {
    if ((0, paths_1.isCanonicalSlug)(rawTaskSlug)) {
        return rawTaskSlug;
    }
    const normalized = (0, paths_1.normalizeCanonicalSlug)(rawTaskSlug);
    if (normalized.kind === "canonical-slug") {
        return normalized.normalizedSlug;
    }
    throw (0, errors_1.createUsageError)(`Invalid task slug '${rawTaskSlug}'.`, [normalized.reason.message]);
}
function extractFrontMatter(filePath, text) {
    const lines = text.split(/\r?\n/);
    if (lines[0] !== "---") {
        throw (0, errors_1.createUsageError)(`File '${filePath}' is missing YAML front matter.`);
    }
    let closingIndex = -1;
    for (let index = 1; index < lines.length; index += 1) {
        if (lines[index] === "---") {
            closingIndex = index;
            break;
        }
    }
    if (closingIndex === -1) {
        throw (0, errors_1.createUsageError)(`File '${filePath}' has malformed YAML front matter.`);
    }
    return {
        lines: lines.slice(1, closingIndex),
        startLineIndex: 0,
        endLineIndex: closingIndex,
        allLines: lines
    };
}
function readTopLevelField(lines, key) {
    for (const line of lines) {
        if (/^\s/.test(line)) {
            continue;
        }
        const match = line.match(/^([A-Za-z0-9_]+):\s*(.*)$/);
        if (match === null) {
            continue;
        }
        if (match[1] === key) {
            return (0, front_matter_utils_1.parseScalar)(match[2]);
        }
    }
    return undefined;
}
function readUpstreamField(lines, key) {
    let inUpstream = false;
    for (const line of lines) {
        if (!inUpstream) {
            if (line.trim() === "upstream:") {
                inUpstream = true;
            }
            continue;
        }
        if (!/^\s/.test(line)) {
            break;
        }
        const match = line.match(/^\s{2}([A-Za-z0-9_]+):\s*(.*)$/);
        if (match !== null && match[1] === key) {
            return (0, front_matter_utils_1.parseScalar)(match[2]);
        }
    }
    return undefined;
}
