"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StructuredProjectReviewError = exports.REVIEW_DISPOSITIONS = exports.closePlans = exports.reviewPlans = void 0;
exports.aggregateStructuredProjectSync = aggregateStructuredProjectSync;
exports.isStructuredOverviewOwnerPath = isStructuredOverviewOwnerPath;
exports.inspectProjectTerminalStateSync = inspectProjectTerminalStateSync;
exports.inspectProjectReviewNavigationEvidence = inspectProjectReviewNavigationEvidence;
exports.reviewedEvidenceMatchesAggregation = reviewedEvidenceMatchesAggregation;
exports.reviewedOverviewRevisionMatches = reviewedOverviewRevisionMatches;
exports.completedOverviewTransitionMatches = completedOverviewTransitionMatches;
// Structured and governed project review aggregation, persistence, and closure orchestration.
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const planning_document_utils_1 = require("../planning/planning-document-utils");
const canonical_write_target_1 = require("../paths/canonical-write-target");
const ordered_root_identity_1 = require("../planning/ordered-root-identity");
const evidence_reading_1 = require("./evidence-reading");
const rendering_and_storage_1 = require("./rendering-and-storage");
exports.reviewPlans = new WeakMap();
exports.closePlans = new WeakMap();
exports.REVIEW_DISPOSITIONS = new Set([
    'accepted',
    'accepted_with_follow_up',
    'changes_requested',
    'blocked',
]);
class StructuredProjectReviewError extends Error {
    code;
    constructor(code, message) {
        super(message);
        this.name = 'StructuredProjectReviewError';
        this.code = code;
    }
}
exports.StructuredProjectReviewError = StructuredProjectReviewError;
function aggregateStructuredProjectSync(options) {
    const repositoryRoot = (0, rendering_and_storage_1.requireRepositoryRoot)(options.repositoryRoot);
    const overviewPath = (0, rendering_and_storage_1.requireRelativePath)(options.overviewPath, 'Project overview path');
    const overviewTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, overviewPath);
    if (!overviewTarget.exists || !node_fs_1.default.statSync(overviewTarget.runtimePath).isFile()) {
        throw new StructuredProjectReviewError('invalid-request', `Project overview '${overviewPath}' does not exist as a canonical file.`);
    }
    const overviewText = node_fs_1.default.readFileSync(overviewTarget.runtimePath, 'utf8');
    const overview = (0, evidence_reading_1.parseOverview)(overviewText, overviewTarget.repositoryRelativePath);
    const workRoot = node_path_1.default.posix.dirname(overviewTarget.repositoryRelativePath);
    const ownerPathValid = overview.workflowLevel === 'structured'
        ? isStructuredOverviewOwnerPath({
            overviewPath: overviewTarget.repositoryRelativePath,
            overviewText,
            ownerId: overview.ownerId,
        })
        : overviewTarget.repositoryRelativePath === `.day-shift/planning/governed/${overview.ownerId}/slice-overview.md`;
    if (!ownerPathValid) {
        throw new StructuredProjectReviewError('invalid-request', `${(0, rendering_and_storage_1.titleLevel)(overview.workflowLevel)} overview '${overviewTarget.repositoryRelativePath}' is not at its canonical owner path.`);
    }
    const findingPrefix = overview.workflowLevel.toUpperCase();
    const levelTitle = (0, rendering_and_storage_1.titleLevel)(overview.workflowLevel);
    const findings = [];
    const specifications = overview.specifications.map((specification) => {
        const target = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, specification.specPath);
        const currentRevision = target.exists && node_fs_1.default.statSync(target.runtimePath).isFile() ? (0, rendering_and_storage_1.revision)(node_fs_1.default.readFileSync(target.runtimePath)) : null;
        const recordedRevision = specification.revision === null ? '' : (0, rendering_and_storage_1.normalizeRevision)(specification.revision);
        const current = specification.revision !== null && currentRevision === recordedRevision;
        if (!current) {
            findings.push((0, rendering_and_storage_1.finding)(specification.revision === null
                ? `${findingPrefix}_SPECIFICATION_REVISION_MISSING`
                : `${findingPrefix}_SPECIFICATION_STALE`, 'error', specification.specPath, specification.revision === null
                ? `${levelTitle} source specification '${specification.specId}' has no recorded overview revision.`
                : currentRevision === null
                    ? `${levelTitle} source specification '${specification.specId}' is missing.`
                    : `${levelTitle} source specification '${specification.specId}' changed after overview creation.`));
        }
        return {
            specId: specification.specId,
            specPath: specification.specPath,
            recordedRevision,
            currentRevision,
            current,
            coveredTaskIds: [],
        };
    });
    const hierarchy = overview.workflowLevel === 'structured'
        ? {
            tasks: (0, evidence_reading_1.readDirectTasks)(repositoryRoot, workRoot, node_path_1.default.resolve(node_path_1.default.join(overviewTarget.runtimePath, '..', 'tasks')), findings),
            reconciliations: [],
            hierarchyArtifacts: [],
        }
        : (0, evidence_reading_1.readGovernedHierarchy)(repositoryRoot, workRoot, overview.ownerId, findings);
    const tasks = hierarchy.tasks;
    const reconciliations = hierarchy.reconciliations;
    const hierarchyArtifacts = hierarchy.hierarchyArtifacts;
    for (const specification of specifications) {
        specification.coveredTaskIds = tasks.map((task) => task.taskId);
        if (tasks.length === 0) {
            findings.push((0, rendering_and_storage_1.finding)(`${findingPrefix}_SPECIFICATION_UNCOVERED`, 'error', specification.specPath, `Specification '${specification.specId}' has no ${overview.workflowLevel === 'structured' ? 'direct Structured' : 'nested Governed'} task coverage.`));
        }
    }
    if (tasks.length === 0) {
        findings.push((0, rendering_and_storage_1.finding)(`${findingPrefix}_TASK_SET_EMPTY`, 'error', node_path_1.default.posix.join(workRoot, overview.workflowLevel === 'structured' ? 'tasks' : 'phases'), `${levelTitle} project review requires at least one ${overview.workflowLevel === 'structured' ? 'direct' : 'nested'} task pair.`));
    }
    const completedTasks = tasks.filter((task) => task.status === 'completed' && task.implementationStatus === 'completed').length;
    const blockedTasks = tasks.filter((task) => task.blockers.length > 0).length;
    for (const task of tasks)
        findings.push(...task.blockers);
    for (const reconciliation of reconciliations)
        findings.push(...reconciliation.blockers);
    const completedReconciliations = reconciliations.filter((entry) => entry.status === 'completed' &&
        entry.reconciliationStatus === 'completed' &&
        entry.placeholderFree &&
        !entry.reviewConcerns &&
        entry.blockers.length === 0).length;
    const closeoutEligible = findings.every((entry) => entry.severity !== 'error') &&
        completedTasks === tasks.length &&
        tasks.every((task) => task.validationEvidence && task.acceptanceEvidence) &&
        (overview.workflowLevel === 'structured' ||
            (reconciliations.length > 0 && completedReconciliations === reconciliations.length));
    const projectReviewPath = node_path_1.default.posix.join(workRoot, 'project-review.md');
    const preliminary = {
        aggregationVersion: 1,
        readOnly: true,
        workflowLevel: overview.workflowLevel,
        ...(overview.workflowLevel === 'structured'
            ? {
                workId: overview.ownerId,
                overviewPath: overviewTarget.repositoryRelativePath,
            }
            : {
                sliceId: overview.ownerId,
                sliceOverviewPath: overviewTarget.repositoryRelativePath,
            }),
        overviewRevision: (0, rendering_and_storage_1.revision)(overviewText),
        overviewStatus: overview.status,
        projectReviewPath,
        projectReviewEvidence: {
            projectReviewPath,
            state: 'not_applicable',
            disposition: null,
            current: false,
            terminal: false,
            reason: 'Terminal project-review evidence has not been projected yet.',
        },
        terminalState: false,
        specifications,
        hierarchyArtifacts,
        tasks,
        reconciliations,
        counts: {
            specifications: specifications.length,
            hierarchyArtifacts: hierarchyArtifacts.length,
            tasks: tasks.length,
            completedTasks,
            blockedTasks,
            tasksWithValidationEvidence: tasks.filter((task) => task.validationEvidence).length,
            tasksWithAcceptanceEvidence: tasks.filter((task) => task.acceptanceEvidence).length,
            reconciliations: reconciliations.length,
            completedReconciliations,
            reconciliationsWithResidualWork: reconciliations.filter((entry) => entry.acceptedResidualWork || entry.followUpWork || entry.deferredWork).length,
            reconciliationsWithWaivers: reconciliations.filter((entry) => entry.waiverEvidence).length,
        },
        findings: (0, rendering_and_storage_1.sortFindings)(findings),
        closeoutEligible,
        nextAction: closeoutEligible
            ? 'Run work review, then explicitly persist an accepted project review.'
            : 'Resolve reported task, reconciliation, evidence, or specification blockers before project closeout.',
        noWriteBoundary: `${levelTitle} aggregation is derived and read-only; it does not repair or mutate overview, hierarchy, task, summary, reconciliation, review, selection, index, or operational state.`,
    };
    const projectReviewEvidence = inspectProjectReviewNavigationEvidence(repositoryRoot, preliminary, overviewText);
    return {
        ...preliminary,
        projectReviewEvidence,
        terminalState: projectReviewEvidence.terminal,
        nextAction: projectReviewEvidence.terminal ? 'No required Governed work action remains.' : preliminary.nextAction,
    };
}
function isStructuredOverviewOwnerPath(input) {
    if (node_path_1.default.posix.basename(input.overviewPath) !== 'overview.md')
        return false;
    const rootPath = node_path_1.default.posix.dirname(input.overviewPath);
    if (node_path_1.default.posix.dirname(rootPath) !== '.day-shift/planning/structured')
        return false;
    try {
        const identity = (0, ordered_root_identity_1.parseOrderedDirectoryIdentity)('structured-root', node_path_1.default.posix.basename(rootPath));
        if (identity.stableId !== input.ownerId)
            return false;
        if (identity.shape === 'legacy')
            return true;
        const document = (0, planning_document_utils_1.parseMarkdownFrontMatter)(input.overviewText);
        return (0, planning_document_utils_1.readTopLevelField)(document.frontMatterLines, 'implementation_order') === identity.orderPrefix;
    }
    catch (error) {
        if (error instanceof ordered_root_identity_1.OrderedRootIdentityError)
            return false;
        throw error;
    }
}
function inspectProjectTerminalStateSync(options) {
    return aggregateStructuredProjectSync(options).projectReviewEvidence;
}
function inspectProjectReviewNavigationEvidence(repositoryRoot, aggregation, overviewText) {
    const base = {
        projectReviewPath: aggregation.projectReviewPath,
        disposition: null,
        current: false,
        terminal: false,
    };
    if (aggregation.workflowLevel !== 'governed' || aggregation.overviewStatus !== 'completed') {
        return {
            ...base,
            state: 'not_applicable',
            reason: 'Terminal projection applies only to a completed Governed slice.',
        };
    }
    const target = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, aggregation.projectReviewPath);
    if (!target.exists || !node_fs_1.default.statSync(target.runtimePath).isFile()) {
        return {
            ...base,
            state: 'missing',
            reason: 'The completed Governed slice has no canonical project-review artifact.',
        };
    }
    let review;
    try {
        review = (0, rendering_and_storage_1.parseProjectReview)(node_fs_1.default.readFileSync(target.runtimePath, 'utf8'), target.repositoryRelativePath);
    }
    catch (error) {
        return {
            ...base,
            state: 'invalid',
            reason: error instanceof Error ? error.message : String(error),
        };
    }
    const disposition = review.disposition;
    const accepted = disposition === 'accepted';
    const identityMatches = review.ownerId === (0, rendering_and_storage_1.aggregationOwnerId)(aggregation) &&
        review.workflowLevel === aggregation.workflowLevel &&
        review.overviewPath === (0, rendering_and_storage_1.aggregationOverviewPath)(aggregation);
    const reviewedEvidenceCurrent = identityMatches && reviewedEvidenceMatchesAggregation(aggregation, review, overviewText);
    const terminal = accepted &&
        reviewedEvidenceCurrent &&
        aggregation.closeoutEligible &&
        aggregation.counts.reconciliationsWithResidualWork === 0;
    return {
        projectReviewPath: aggregation.projectReviewPath,
        state: terminal ? 'current_accepted' : 'stale',
        disposition,
        current: reviewedEvidenceCurrent,
        terminal,
        reason: terminal
            ? 'The completed Governed slice has current accepted project-review evidence and clean terminal descendants.'
            : !identityMatches
                ? 'Project-review identity does not match the completed Governed slice.'
                : !accepted
                    ? `Project-review disposition '${disposition}' is not terminal accepted evidence.`
                    : !reviewedEvidenceCurrent
                        ? 'Project-review evidence is stale relative to the current Governed hierarchy.'
                        : 'Current reconciliation evidence still contains residual or follow-up work.',
    };
}
function reviewedEvidenceMatchesAggregation(aggregation, review, overviewText) {
    if (!reviewedOverviewRevisionMatches(aggregation, review, overviewText))
        return false;
    if (review.reviewedEvidence.specifications.length !== aggregation.specifications.length ||
        review.reviewedEvidence.hierarchyArtifacts.length !== aggregation.hierarchyArtifacts.length ||
        review.reviewedEvidence.tasks.length !== aggregation.tasks.length ||
        review.reviewedEvidence.reconciliations.length !== aggregation.reconciliations.length) {
        return false;
    }
    const specifications = new Map(aggregation.specifications.map((entry) => [entry.specPath, entry]));
    if (!review.reviewedEvidence.specifications.every((entry) => {
        const current = specifications.get(entry.specPath);
        return (current !== undefined &&
            current.specId === entry.specId &&
            current.currentRevision === (0, rendering_and_storage_1.normalizeRevision)(entry.revision));
    }))
        return false;
    const hierarchy = new Map(aggregation.hierarchyArtifacts.map((entry) => [entry.artifactPath, entry]));
    if (!review.reviewedEvidence.hierarchyArtifacts.every((entry) => {
        const current = hierarchy.get(entry.artifactPath);
        return (current !== undefined &&
            current.artifactType === entry.artifactType &&
            (current.artifactRevision === entry.artifactRevision ||
                (entry.artifactPath === (0, rendering_and_storage_1.aggregationOverviewPath)(aggregation) &&
                    completedOverviewTransitionMatches(aggregation, overviewText, entry.artifactRevision))));
    }))
        return false;
    const tasks = new Map(aggregation.tasks.map((entry) => [entry.taskDefinitionPath, entry]));
    if (!review.reviewedEvidence.tasks.every((entry) => {
        const current = tasks.get(entry.taskDefinitionPath);
        return (current !== undefined &&
            current.taskId === entry.taskId &&
            current.taskDefinitionRevision === entry.taskDefinitionRevision &&
            current.implementationSummaryRevision === entry.implementationSummaryRevision);
    }))
        return false;
    const reconciliations = new Map(aggregation.reconciliations.map((entry) => [entry.reconciliationPath, entry]));
    return review.reviewedEvidence.reconciliations.every((entry) => {
        const current = reconciliations.get(entry.reconciliationPath);
        return (current !== undefined &&
            current.milestoneId === entry.milestoneId &&
            current.milestoneOverviewPath === entry.milestoneOverviewPath &&
            current.reconciliationRevision === entry.reconciliationRevision &&
            current.acceptedResidualWork === entry.acceptedResidualWork &&
            current.followUpWork === entry.followUpWork &&
            current.deferredWork === entry.deferredWork &&
            current.waiverEvidence === entry.waiverEvidence);
    });
}
function reviewedOverviewRevisionMatches(aggregation, review, overviewText) {
    if (review.reviewedEvidence.overviewRevision === aggregation.overviewRevision)
        return true;
    return completedOverviewTransitionMatches(aggregation, overviewText, review.reviewedEvidence.overviewRevision);
}
function completedOverviewTransitionMatches(aggregation, overviewText, reviewedRevision) {
    if (aggregation.workflowLevel !== 'governed' || aggregation.overviewStatus !== 'completed') {
        return false;
    }
    return ['draft', 'active'].some((priorStatus) => (0, rendering_and_storage_1.revision)((0, rendering_and_storage_1.replaceOverviewStatusValue)(overviewText, priorStatus)) === reviewedRevision);
}
