"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 {
        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;
}
