"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.inspectAuthoredMilestoneScaffold = inspectAuthoredMilestoneScaffold;
exports.inspectMilestoneCriterionOwnership = inspectMilestoneCriterionOwnership;
const errors_1 = require("../../errors");
const paths_1 = require("../../paths");
const authoring_policy_1 = require("../authoring-policy");
const planning_document_utils_1 = require("../planning-document-utils");
const support_rendering_1 = require("./support-rendering");
const task_evidence_1 = require("./task-evidence");
function inspectAuthoredMilestoneScaffold(options) {
    const scopedLines = (0, task_evidence_1.readMilestoneTopLevelEvidence)(options.phaseMarkdownText, options.milestoneSlug);
    const issues = [];
    const taskCountValue = (0, task_evidence_1.singleSemanticValue)(scopedLines, "target_task_count")
        ?? (0, task_evidence_1.singleSemanticValue)(scopedLines, "task_count");
    const parsedTaskCount = taskCountValue === null
        ? Number.NaN
        : Number.parseInt(taskCountValue, 10);
    if (taskCountValue === null
        || !/^\d+$/u.test(taskCountValue)
        || !Number.isSafeInteger(parsedTaskCount)
        || parsedTaskCount < 1) {
        issues.push(`Milestone '${options.milestoneSlug}' must declare a positive integer task_count in its Scaffold Evidence block.`);
    }
    const decompositionRationale = (0, task_evidence_1.singleSemanticValue)(scopedLines, "decomposition_rationale");
    if (decompositionRationale === null) {
        issues.push(`Milestone '${options.milestoneSlug}' must declare an authored decomposition_rationale in its Scaffold Evidence block.`);
    }
    const nestedTasks = (0, task_evidence_1.readNestedMilestoneTasks)(options.phaseMarkdownText, options.milestoneSlug, issues, options.runtimeEvidencePathPolicy);
    const authoredTasks = nestedTasks.length > 0
        ? [...nestedTasks]
        : (0, task_evidence_1.semanticValuesPreservingDelimiters)(scopedLines, "task")
            .map((value) => (0, task_evidence_1.parseAuthoredTask)(value, options.milestoneSlug, issues))
            .filter((task) => task !== null);
    const authoredTaskSlug = (0, task_evidence_1.singleSemanticValue)(scopedLines, "task_slug");
    const authoredTaskDescription = (0, task_evidence_1.singleSemanticValue)(scopedLines, "task_description");
    if (authoredTaskSlug !== null || authoredTaskDescription !== null) {
        if (authoredTaskSlug === null || !(0, paths_1.isCanonicalSlug)(authoredTaskSlug)) {
            issues.push(`Milestone '${options.milestoneSlug}' task_slug must be a canonical slug.`);
        }
        if (authoredTaskDescription === null) {
            issues.push(`Milestone '${options.milestoneSlug}' must pair task_slug with task_description.`);
        }
        if (authoredTaskSlug !== null
            && (0, paths_1.isCanonicalSlug)(authoredTaskSlug)
            && authoredTaskDescription !== null) {
            authoredTasks.push({
                slug: authoredTaskSlug,
                description: authoredTaskDescription,
                ...(0, task_evidence_1.taskEvidenceFromMilestone)(options.scaffoldEvidence)
            });
        }
    }
    const taskCount = Number.isSafeInteger(parsedTaskCount) && parsedTaskCount > 0
        ? parsedTaskCount
        : 0;
    let tasks = authoredTasks;
    if (tasks.length === 0 && taskCount === 1) {
        const description = (0, task_evidence_1.concreteTaskDescription)(options.milestoneDescription, options.scaffoldEvidence.ownership);
        if (description === null) {
            issues.push(`Milestone '${options.milestoneSlug}' needs either an authored task entry or concrete ownership evidence from which one implementation task can be generated.`);
        }
        else {
            tasks = [{
                    slug: (0, support_rendering_1.resolveMilestoneTaskCandidateSlug)(options.milestoneSlug),
                    description,
                    ...(0, task_evidence_1.taskEvidenceFromMilestone)(options.scaffoldEvidence)
                }];
        }
    }
    else if (tasks.length === 0 && taskCount > 1) {
        issues.push(`Milestone '${options.milestoneSlug}' declares task_count ${taskCount}; declare each child as 'task: <slug> | <description>' instead of inventing task boundaries.`);
    }
    if (taskCount > 0 && tasks.length !== taskCount) {
        issues.push(`Milestone '${options.milestoneSlug}' task_count ${taskCount} contradicts ${tasks.length} authored or safely generated task candidate${tasks.length === 1 ? "" : "s"}.`);
    }
    const duplicateTaskSlugs = tasks
        .map((task) => task.slug)
        .filter((slug, index, all) => all.indexOf(slug) !== index);
    if (duplicateTaskSlugs.length > 0) {
        issues.push(`Milestone '${options.milestoneSlug}' repeats task slugs: ${[...new Set(duplicateTaskSlugs)].join(", ")}.`);
    }
    const taskSlugValidation = (0, planning_document_utils_1.validateDeclaredChildSlugSection)(tasks.map((task) => `- \`${task.slug}\`: ${task.description}`).join("\n"));
    issues.push(...taskSlugValidation.issues.map((issue) => `Milestone '${options.milestoneSlug}' task declaration is not scaffold-ready: ${issue.message}`));
    if (decompositionRationale !== null && taskCount > 0 && tasks.length === taskCount) {
        const decompositionIssues = (0, authoring_policy_1.auditParentDecomposition)({
            artifactPath: options.parentPath,
            markdownText: [
                `Target task count: ${taskCount}.`,
                `Decomposition rationale: ${decompositionRationale}`,
                ...tasks.map((task) => `- \`${task.slug}\`: ${task.description}`)
            ].join("\n"),
            childKind: "task",
            declaredChildSlugs: tasks.map((task) => task.slug)
        });
        issues.push(...decompositionIssues.map((issue) => `Milestone '${options.milestoneSlug}' decomposition is not task-scaffold-ready: ${issue.reason}`));
    }
    const criterionReview = inspectMilestoneCriterionOwnership({
        phaseMarkdownText: options.phaseMarkdownText,
        declaredMilestoneSlugs: options.declaredMilestoneSlugs,
        phaseAcceptanceCriteria: options.phaseAcceptanceCriteria,
        authoritativeCriterionIds: options.authoritativeCriterionIds
    });
    issues.push(...criterionReview.issues);
    const assignedCriterionIds = criterionReview.criterionIdsByMilestone
        .get(options.milestoneSlug) ?? [];
    const assignedAcceptanceCriteria = criterionReview.acceptanceByMilestone
        .get(options.milestoneSlug) ?? [];
    if (tasks.length === 1
        && tasks[0].criterionIds.length === 0
        && assignedCriterionIds.length > 0) {
        tasks = [{ ...tasks[0], criterionIds: [...assignedCriterionIds] }];
    }
    if (options.allowIncompleteProjectedTaskEvidence !== true) {
        for (const task of tasks) {
            const ownership = task.ownership.length > 0
                ? task.ownership
                : options.scaffoldEvidence.ownership;
            const projectedEvidence = (0, authoring_policy_1.inspectProjectedTaskScaffoldEvidence)({
                prose: [
                    task.description,
                    ...task.acceptanceCriteria,
                    task.currentBehavior ?? "",
                    task.desiredBehavior,
                    ...ownership
                ],
                ownership,
                dependencies: task.dependencies.length > 0
                    ? task.dependencies
                    : options.scaffoldEvidence.dependencies,
                targetPaths: task.targetPaths.length > 0
                    ? task.targetPaths
                    : options.scaffoldEvidence.targetPaths,
                explicitAdapterPaths: task.adapterPaths.length > 0
                    ? task.adapterPaths
                    : options.scaffoldEvidence.adapterPaths,
                validationCommands: task.validationCommands.length > 0
                    ? task.validationCommands
                    : options.scaffoldEvidence.validationCommands,
                rollback: task.rollback.length > 0
                    ? task.rollback
                    : options.scaffoldEvidence.rollback
            });
            if (projectedEvidence.missingEvidence.includes("adapter")) {
                issues.push(`Milestone '${options.milestoneSlug}' task '${task.slug}' requires an explicit adapter path for its command-facing behavior.`);
            }
        }
    }
    if (issues.length > 0) {
        throw (0, errors_1.createInvalidConfigError)(`Planning scaffold refinement is required before milestone '${options.milestoneSlug}' can be created.`, [
            ...(0, task_evidence_1.uniqueStrings)(issues).map((issue) => `${options.parentPath}: ${issue}`),
            "No milestone artifact write was attempted."
        ], (0, task_evidence_1.uniqueStrings)(issues).map((issue) => ({
            code: "PLANNING_MILESTONE_SCAFFOLD_NOT_READY",
            message: issue,
            severity: "error",
            path: options.parentPath,
            evidence: {
                category: "planning-review",
                details: {
                    childKind: "milestone",
                    childSlug: options.milestoneSlug,
                    requiresRefinement: true,
                    noWriteRequired: true
                }
            }
        })));
    }
    const acceptanceCriteria = assignedAcceptanceCriteria.length > 0
        ? assignedAcceptanceCriteria
        : options.milestoneDescription === ""
            ? []
            : [(0, support_rendering_1.ensureTerminalPunctuation)(options.milestoneDescription)];
    const taskCriterionIssues = (0, task_evidence_1.inspectTaskCriterionOwnership)({
        milestoneSlug: options.milestoneSlug,
        milestoneCriterionIds: assignedCriterionIds,
        tasks
    });
    if (taskCriterionIssues.length > 0) {
        throw (0, errors_1.createInvalidConfigError)(`Planning scaffold refinement is required before milestone '${options.milestoneSlug}' can be created.`, [
            ...taskCriterionIssues.map((issue) => `${options.parentPath}: ${issue}`),
            "No milestone artifact write was attempted."
        ], taskCriterionIssues.map((issue) => ({
            code: "PLANNING_MILESTONE_TASK_CRITERION_OWNERSHIP_INVALID",
            message: issue,
            severity: "error",
            path: options.parentPath,
            evidence: {
                category: "planning-review",
                details: {
                    childKind: "milestone",
                    childSlug: options.milestoneSlug,
                    requiresRefinement: true,
                    noWriteRequired: true
                }
            }
        })));
    }
    return {
        taskCount,
        decompositionRationale: decompositionRationale ?? "",
        tasks,
        criterionIds: assignedCriterionIds,
        acceptanceCriteria
    };
}
function inspectMilestoneCriterionOwnership(options) {
    const issues = [];
    const criterionIdsByMilestone = new Map();
    const acceptanceByMilestone = new Map();
    const criterionEntries = options.phaseAcceptanceCriteria.map((criterion) => ({
        criterion,
        id: (0, task_evidence_1.acceptanceCriterionId)(criterion)
    }));
    const bodyCriterionIds = criterionEntries
        .map((entry) => entry.id)
        .filter((id) => id !== null);
    const parentCriterionIds = options.authoritativeCriterionIds.length > 0
        ? [...options.authoritativeCriterionIds]
        : bodyCriterionIds;
    if (bodyCriterionIds.length > 0
        && bodyCriterionIds.length !== options.phaseAcceptanceCriteria.length) {
        issues.push("Phase acceptance criteria mix identified and unidentified entries; every criterion must use a stable ID before reviewed per-milestone ownership can be projected.");
    }
    if (parentCriterionIds.length > 0) {
        const parentIds = new Set(parentCriterionIds);
        const sharedByMilestone = new Map();
        const assignedCriterionIds = new Set();
        for (const milestoneSlug of options.declaredMilestoneSlugs) {
            const scopedLines = (0, task_evidence_1.readMilestoneTopLevelEvidence)(options.phaseMarkdownText, milestoneSlug);
            const criterionIds = (0, task_evidence_1.semanticListValues)(scopedLines, "criterion_ids");
            const sharedCriterionIds = (0, task_evidence_1.semanticListValues)(scopedLines, "shared_criterion_ids");
            criterionIdsByMilestone.set(milestoneSlug, criterionIds);
            sharedByMilestone.set(milestoneSlug, sharedCriterionIds);
            if (criterionIds.length === 0) {
                issues.push(`Milestone '${milestoneSlug}' must declare a non-empty criterion_ids subset in Scaffold Evidence.`);
            }
            const unknown = criterionIds.filter((id) => !parentIds.has(id));
            if (unknown.length > 0) {
                issues.push(`Milestone '${milestoneSlug}' assigns criterion_ids outside the phase contract: ${(0, task_evidence_1.uniqueStrings)(unknown).join(", ")}.`);
            }
            const invalidShared = sharedCriterionIds.filter((id) => !criterionIds.includes(id));
            if (invalidShared.length > 0) {
                issues.push(`Milestone '${milestoneSlug}' marks shared_criterion_ids it does not own: ${(0, task_evidence_1.uniqueStrings)(invalidShared).join(", ")}.`);
            }
            const duplicates = criterionIds.filter((id, index) => criterionIds.indexOf(id) !== index);
            if (duplicates.length > 0) {
                issues.push(`Milestone '${milestoneSlug}' repeats criterion_ids: ${(0, task_evidence_1.uniqueStrings)(duplicates).join(", ")}.`);
            }
            const expectedChildOrder = parentCriterionIds.filter((id) => criterionIds.includes(id));
            const knownChildOrder = criterionIds.filter((id) => parentIds.has(id));
            if (!(0, task_evidence_1.sameOrderedValues)(knownChildOrder, expectedChildOrder)) {
                issues.push(`Milestone '${milestoneSlug}' criterion_ids must preserve their relative phase order: ${expectedChildOrder.join(", ")}.`);
            }
            for (const criterionId of criterionIds) {
                if (parentIds.has(criterionId))
                    assignedCriterionIds.add(criterionId);
            }
            acceptanceByMilestone.set(milestoneSlug, criterionIds.map((criterionId) => {
                const match = criterionEntries.find((entry) => entry.id === criterionId);
                return match?.criterion
                    ?? `[${criterionId}] Satisfy the reviewed phase criterion owned by this milestone.`;
            }));
        }
        const omitted = parentCriterionIds.filter((id) => !assignedCriterionIds.has(id));
        if (omitted.length > 0) {
            issues.push(`Milestone criterion assignments omit phase criteria: ${omitted.join(", ")}.`);
        }
        for (const criterionId of parentCriterionIds) {
            const owners = options.declaredMilestoneSlugs.filter((milestoneSlug) => criterionIdsByMilestone.get(milestoneSlug)?.includes(criterionId));
            if (owners.length < 2)
                continue;
            const unreviewed = owners.filter((milestoneSlug) => !(sharedByMilestone.get(milestoneSlug) ?? []).includes(criterionId));
            if (unreviewed.length > 0) {
                issues.push(`Criterion '${criterionId}' overlaps across ${owners.join(", ")} without shared_criterion_ids review from: ${unreviewed.join(", ")}.`);
            }
        }
    }
    else if (options.phaseAcceptanceCriteria.length > 0) {
        const orderedUnion = [];
        for (const milestoneSlug of options.declaredMilestoneSlugs) {
            const scopedLines = (0, task_evidence_1.readMilestoneTopLevelEvidence)(options.phaseMarkdownText, milestoneSlug);
            const acceptance = (0, task_evidence_1.semanticValuesPreservingDelimiters)(scopedLines, "acceptance");
            acceptanceByMilestone.set(milestoneSlug, acceptance);
            if (acceptance.length === 0) {
                issues.push(`Milestone '${milestoneSlug}' must declare child-specific acceptance evidence because the phase criteria do not have stable IDs.`);
            }
            for (const entry of acceptance) {
                if (!orderedUnion.includes(entry))
                    orderedUnion.push(entry);
            }
        }
        const unknown = orderedUnion.filter((entry) => !options.phaseAcceptanceCriteria.includes(entry));
        const omitted = options.phaseAcceptanceCriteria.filter((entry) => !orderedUnion.includes(entry));
        if (unknown.length > 0 || omitted.length > 0) {
            issues.push("Child-specific acceptance evidence must exactly cover the ordered phase acceptance criteria when stable criterion IDs are unavailable.");
        }
        else if (!(0, task_evidence_1.sameOrderedValues)(orderedUnion, options.phaseAcceptanceCriteria)) {
            issues.push("The ordered milestone acceptance union must preserve phase criterion order.");
        }
    }
    return {
        criterionIdsByMilestone,
        acceptanceByMilestone,
        issues: (0, task_evidence_1.uniqueStrings)(issues)
    };
}
