"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.reviewStructuredProjectSync = reviewStructuredProjectSync;
exports.previewStructuredProjectReviewPersistenceSync = previewStructuredProjectReviewPersistenceSync;
exports.applyStructuredProjectReviewPersistenceSync = applyStructuredProjectReviewPersistenceSync;
exports.previewStructuredFollowUpCreationSync = previewStructuredFollowUpCreationSync;
exports.applyStructuredFollowUpCreationSync = applyStructuredFollowUpCreationSync;
exports.previewStructuredProjectClosureSync = previewStructuredProjectClosureSync;
exports.applyStructuredProjectClosureSync = applyStructuredProjectClosureSync;
// Structured and governed project review aggregation, persistence, and closure orchestration.
const node_fs_1 = __importDefault(require("node:fs"));
const mutation_preconditions_1 = require("../filesystem/mutation-preconditions");
const canonical_write_target_1 = require("../paths/canonical-write-target");
const work_creation_1 = require("../work-creation");
const contracts_and_aggregation_1 = require("./contracts-and-aggregation");
const evidence_reading_1 = require("./evidence-reading");
const rendering_and_storage_1 = require("./rendering-and-storage");
function reviewStructuredProjectSync(options) {
    const aggregation = (0, contracts_and_aggregation_1.aggregateStructuredProjectSync)(options);
    const findingPrefix = aggregation.workflowLevel.toUpperCase();
    const levelTitle = (0, rendering_and_storage_1.titleLevel)(aggregation.workflowLevel);
    const findings = [...aggregation.findings];
    for (const task of aggregation.tasks) {
        if (task.status !== 'completed' || task.implementationStatus !== 'completed') {
            findings.push((0, rendering_and_storage_1.finding)(`${findingPrefix}_TASK_INCOMPLETE`, 'error', task.taskDefinitionPath, `Task '${task.taskId}' is not fully completed in its canonical task pair.`));
        }
        if (!task.validationEvidence) {
            findings.push((0, rendering_and_storage_1.finding)(`${findingPrefix}_VALIDATION_EVIDENCE_MISSING`, 'error', task.implementationSummaryPath, `Task '${task.taskId}' lacks non-placeholder validation evidence.`));
        }
        if (!task.acceptanceEvidence) {
            findings.push((0, rendering_and_storage_1.finding)(`${findingPrefix}_ACCEPTANCE_EVIDENCE_MISSING`, 'error', task.implementationSummaryPath, `Task '${task.taskId}' lacks non-placeholder acceptance evidence.`));
        }
    }
    const sorted = (0, rendering_and_storage_1.sortFindings)(findings);
    const closeoutEligible = sorted.every((entry) => entry.severity !== 'error');
    const hasResidualWork = aggregation.counts.reconciliationsWithResidualWork > 0;
    return {
        reviewVersion: 1,
        readOnly: true,
        aggregation,
        findings: sorted,
        specificationCoverage: aggregation.specifications,
        closeoutEligible,
        recommendedDisposition: closeoutEligible
            ? hasResidualWork
                ? 'accepted_with_follow_up'
                : 'accepted'
            : 'changes_requested',
        nextAction: closeoutEligible
            ? `Preview project-review persistence for '${aggregation.projectReviewPath}'.`
            : 'Resolve blocking review findings and rerun read-only project review.',
        noWriteBoundary: `${levelTitle} project review is findings-oriented and write-free; persistence, follow-up creation, lifecycle mutation, and closure require separate explicit preview/apply commands.`,
    };
}
function previewStructuredProjectReviewPersistenceSync(request) {
    const repositoryRoot = (0, rendering_and_storage_1.requireRepositoryRoot)(request.repositoryRoot);
    const disposition = (0, rendering_and_storage_1.normalizeDisposition)(request.disposition);
    const reviewer = (0, rendering_and_storage_1.requireText)(request.reviewer, 'Project reviewer');
    const summary = (0, rendering_and_storage_1.requireText)(request.summary, 'Project review summary');
    const followUpTasks = [...(request.followUpTasks ?? [])];
    const review = reviewStructuredProjectSync({
        repositoryRoot,
        overviewPath: request.overviewPath,
    });
    if ((disposition === 'accepted' || disposition === 'accepted_with_follow_up') && !review.closeoutEligible) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('not-closeable', `Disposition '${disposition}' is invalid while blocking ${(0, rendering_and_storage_1.titleLevel)(review.aggregation.workflowLevel)} review findings remain.`);
    }
    const governed = review.aggregation.workflowLevel === 'governed';
    const governedResidualWork = review.aggregation.counts.reconciliationsWithResidualWork > 0;
    if (!governed && disposition === 'accepted_with_follow_up' && followUpTasks.length === 0) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', "Disposition 'accepted_with_follow_up' requires at least one complete follow-up task contract.");
    }
    if (governed && followUpTasks.length > 0) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', 'Governed follow-up disposition is owned by completed milestone reconciliation evidence; direct follow-up task contracts require an explicit destination milestone and are not created by this command.');
    }
    if (governed && disposition === 'accepted_with_follow_up' && !governedResidualWork) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', "Governed disposition 'accepted_with_follow_up' requires inspectable residual, follow-up, or deferred-work evidence in a completed milestone reconciliation.");
    }
    if (governed && disposition === 'accepted' && governedResidualWork) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', "Governed reconciliation evidence contains residual or follow-up work; record disposition 'accepted_with_follow_up'.");
    }
    if (disposition !== 'accepted_with_follow_up' && followUpTasks.length > 0) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', "Follow-up task contracts require disposition 'accepted_with_follow_up'.");
    }
    if (!governed && followUpTasks.length > 0) {
        (0, work_creation_1.previewStructuredTaskPairCreationSync)({
            repositoryRoot,
            overviewPath: (0, rendering_and_storage_1.aggregationOverviewPath)(review.aggregation),
            tasks: followUpTasks,
        });
    }
    const target = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, review.aggregation.projectReviewPath);
    if (target.exists) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('destination-conflict', `Canonical ${(0, rendering_and_storage_1.titleLevel)(review.aggregation.workflowLevel)} project review already exists at '${target.repositoryRelativePath}'.`);
    }
    const preconditions = (0, evidence_reading_1.aggregationPreconditions)(repositoryRoot, review.aggregation, true);
    const contents = (0, rendering_and_storage_1.renderProjectReview)({ review, disposition, reviewer, summary, followUpTasks });
    const result = (0, rendering_and_storage_1.previewMutationResult)(review.aggregation, 'project-review-create', disposition, preconditions, [target.repositoryRelativePath], `Apply this preview to create the canonical ${(0, rendering_and_storage_1.titleLevel)(review.aggregation.workflowLevel)} project review.`);
    contracts_and_aggregation_1.reviewPlans.set(result, {
        repositoryRoot,
        writes: [{ path: target.repositoryRelativePath, contents }],
        preconditions,
    });
    return result;
}
function applyStructuredProjectReviewPersistenceSync(preview, options = {}) {
    return (0, rendering_and_storage_1.applyMutation)(preview, contracts_and_aggregation_1.reviewPlans, options, 'project-review persistence');
}
function previewStructuredFollowUpCreationSync(options) {
    const repositoryRoot = (0, rendering_and_storage_1.requireRepositoryRoot)(options.repositoryRoot);
    const projectReviewPath = (0, rendering_and_storage_1.requireRelativePath)(options.projectReviewPath, 'Project review path');
    const reviewTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, projectReviewPath);
    if (!reviewTarget.exists || !node_fs_1.default.statSync(reviewTarget.runtimePath).isFile()) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', `Canonical project review '${projectReviewPath}' does not exist.`);
    }
    const review = (0, rendering_and_storage_1.parseProjectReview)(node_fs_1.default.readFileSync(reviewTarget.runtimePath, 'utf8'), reviewTarget.repositoryRelativePath);
    if (review.workflowLevel !== 'structured') {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', 'Direct follow-up task creation is available only for Structured project reviews; Governed follow-up work must name an explicit destination milestone in a separately authorized planning action.');
    }
    if (review.disposition !== 'accepted_with_follow_up') {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', 'Follow-up task creation requires an accepted_with_follow_up project review.');
    }
    const requested = (0, rendering_and_storage_1.normalizeSelectedTaskIds)(options.taskIds);
    const selected = review.followUpTasks.filter((task) => requested.includes(task.taskId));
    const declared = new Set(review.followUpTasks.map((task) => task.taskId));
    const undeclared = requested.filter((taskId) => !declared.has(taskId));
    if (undeclared.length > 0 || selected.length !== requested.length) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', `Follow-up task selection contains undeclared or duplicate ids: ${undeclared.join(', ') || requested.join(', ')}.`);
    }
    return (0, work_creation_1.previewStructuredTaskPairCreationSync)({
        repositoryRoot,
        overviewPath: review.overviewPath,
        tasks: selected,
        sourceProjectReviewPath: reviewTarget.repositoryRelativePath,
    });
}
function applyStructuredFollowUpCreationSync(preview, options = {}) {
    return (0, work_creation_1.applyStructuredTaskPairCreationSync)(preview, options);
}
function previewStructuredProjectClosureSync(options) {
    const repositoryRoot = (0, rendering_and_storage_1.requireRepositoryRoot)(options.repositoryRoot);
    const aggregation = (0, contracts_and_aggregation_1.aggregateStructuredProjectSync)({
        repositoryRoot,
        overviewPath: options.overviewPath,
    });
    const reviewPath = (0, rendering_and_storage_1.requireRelativePath)(options.projectReviewPath, 'Project review path');
    if (reviewPath !== aggregation.projectReviewPath) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', `Project review must match '${aggregation.projectReviewPath}'.`);
    }
    const reviewTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, reviewPath);
    if (!reviewTarget.exists || !node_fs_1.default.statSync(reviewTarget.runtimePath).isFile()) {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', `Project review '${reviewPath}' is missing.`);
    }
    const review = (0, rendering_and_storage_1.parseProjectReview)(node_fs_1.default.readFileSync(reviewTarget.runtimePath, 'utf8'), reviewTarget.repositoryRelativePath);
    (0, rendering_and_storage_1.validateClosure)(aggregation, review);
    const overviewPath = (0, rendering_and_storage_1.aggregationOverviewPath)(aggregation);
    const overviewTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, overviewPath);
    const overviewText = node_fs_1.default.readFileSync(overviewTarget.runtimePath, 'utf8');
    if (aggregation.overviewStatus === 'completed') {
        throw new contracts_and_aggregation_1.StructuredProjectReviewError('invalid-request', `${(0, rendering_and_storage_1.titleLevel)(aggregation.workflowLevel)} project is already completed.`);
    }
    const preconditions = [
        ...(0, evidence_reading_1.aggregationPreconditions)(repositoryRoot, aggregation, false),
        (0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(overviewTarget),
        (0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(reviewTarget),
    ];
    const result = (0, rendering_and_storage_1.previewMutationResult)(aggregation, 'project-close', review.disposition, preconditions, [overviewPath], `Apply this preview to close only the canonical ${(0, rendering_and_storage_1.titleLevel)(aggregation.workflowLevel)} overview.`);
    contracts_and_aggregation_1.closePlans.set(result, {
        repositoryRoot,
        writes: [{ path: overviewPath, contents: (0, rendering_and_storage_1.replaceOverviewStatus)(overviewText) }],
        preconditions,
    });
    return result;
}
function applyStructuredProjectClosureSync(preview, options = {}) {
    return (0, rendering_and_storage_1.applyMutation)(preview, contracts_and_aggregation_1.closePlans, options, 'project closure');
}
