"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.previewSpecificationReadinessDispositionSync = previewSpecificationReadinessDispositionSync;
exports.applySpecificationReadinessDispositionSync = applySpecificationReadinessDispositionSync;
const mutation_preconditions_1 = require("../filesystem/mutation-preconditions");
const repository_transaction_1 = require("../filesystem/repository-transaction");
const canonical_write_target_1 = require("../paths/canonical-write-target");
const spec_review_1 = require("../spec-review");
const review_normalization_1 = require("./review-normalization");
const repository_1 = require("./repository");
const types_1 = require("./types");
const plans = new WeakMap();
/** Creates an in-memory revision-bound write plan. No file is written. */
function previewSpecificationReadinessDispositionSync(request) {
    if (request === null || typeof request !== "object") {
        throw new types_1.SpecificationReadinessError("invalid-input", "A readiness disposition request is required.");
    }
    const specification = (0, repository_1.resolveRegisteredSpecification)(request.repositoryRoot, request.specPath);
    const recordedAt = (0, repository_1.requireTimestamp)(request.recordedAt, "Disposition time");
    const recordedBy = (0, repository_1.requireNonEmpty)(request.recordedBy, "Disposition actor");
    const preconditions = [
        (0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(specification.specTarget),
        (0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(specification.specTarget)
    ];
    const writes = [];
    let review = null;
    let waiver = null;
    let reason;
    if (request.planningReadiness === "ready") {
        const normalized = (0, review_normalization_1.normalizeSpecificationReviewResultSync)(specification.repositoryRoot, specification.specPath, request.reviewResult, request.reviewDigest);
        if (normalized.result.protocol_version !== spec_review_1.SPECIFICATION_REVIEW_PROTOCOL_VERSION) {
            throw new types_1.SpecificationReadinessError("unsupported-protocol", `New ready dispositions require current review protocol '${spec_review_1.SPECIFICATION_REVIEW_PROTOCOL_VERSION}'.`);
        }
        if (normalized.result.planning_readiness_recommendation.status !== "ready" ||
            normalized.result.counts.unresolved !== 0 ||
            normalized.result.unresolved_findings.length !== 0) {
            throw new types_1.SpecificationReadinessError("review-invalid", "A ready disposition requires a complete review with no unresolved findings and a ready recommendation.");
        }
        reason = (0, repository_1.optionalNonEmpty)(request.reason, "Disposition reason");
        const reviewRef = `reviews/${normalized.result.review_id}.json`;
        const reviewPath = (0, repository_1.posixJoin)(specification.specPath, "..", reviewRef);
        const reviewTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(specification.repositoryRoot, reviewPath);
        addWritePreconditions(preconditions, reviewTarget);
        review = {
            id: normalized.result.review_id,
            ref: reviewRef,
            path: reviewTarget.repositoryRelativePath,
            digest: normalized.digest,
            protocolVersion: normalized.result.protocol_version,
            reviewedAt: normalized.result.reviewed_at,
            reviewedBy: normalized.result.reviewed_by,
            recommendedWorkflowLevel: normalized.result.workflow_level_recommendation.level
        };
        writes.push({ path: review.path, contents: normalized.canonicalJson });
    }
    else if (request.planningReadiness === "waived") {
        waiver = (0, repository_1.validateWaiver)(request.waiver, specification.specId, true);
        reason = (0, repository_1.optionalNonEmpty)(request.reason, "Disposition reason") ?? waiver.reason;
    }
    else if (request.planningReadiness === "revoked") {
        reason = (0, repository_1.requireNonEmpty)(request.reason, "Revocation reason");
    }
    else {
        throw new types_1.SpecificationReadinessError("invalid-input", "Unsupported planning-readiness disposition.");
    }
    addWritePreconditions(preconditions, specification.dispositionTarget);
    writes.push({
        path: specification.dispositionTarget.repositoryRelativePath,
        contents: renderDispositionDocument({
            specification,
            planningReadiness: request.planningReadiness,
            recordedAt,
            recordedBy,
            reason,
            review,
            waiver
        })
    });
    const intendedPaths = writes.map((write) => write.path).sort(repository_1.comparePosix);
    const preview = {
        specId: specification.specId,
        specPath: specification.specPath,
        specRevision: specification.specRevision,
        planningReadiness: request.planningReadiness,
        dispositionPath: specification.dispositionTarget.repositoryRelativePath,
        review,
        waiver,
        intendedPaths,
        changedPaths: [],
        expected: preconditions.map(toExpectedCondition),
        writeOutcome: "previewed",
        transactionId: null,
        conflicts: [],
        recoveryPath: null,
        failure: null
    };
    plans.set(preview, { repositoryRoot: specification.repositoryRoot, writes, preconditions });
    return preview;
}
/** Applies only the original in-process preview through the repository transaction service. */
function applySpecificationReadinessDispositionSync(preview, options = {}) {
    const plan = plans.get(preview);
    if (plan === undefined) {
        throw new types_1.SpecificationReadinessError("stale-preview", "Readiness disposition apply requires the original in-process preview. Refresh the preview.");
    }
    const transaction = (0, repository_transaction_1.executeRepositoryTransactionSync)(plan.repositoryRoot, { writes: plan.writes, preconditions: plan.preconditions }, options.transaction);
    return {
        ...preview,
        writeOutcome: transaction.outcome,
        changedPaths: transaction.entries.slice(0, transaction.canonicalWrites).map((entry) => entry.path),
        transactionId: transaction.transactionId,
        conflicts: transaction.conflicts,
        recoveryPath: transaction.outcome === "incomplete" ? transaction.transactionPath : null,
        failure: transaction.failure
    };
}
function renderDispositionDocument(input) {
    const lines = [
        "---",
        `artifact_schema_version: ${types_1.SPECIFICATION_PLANNING_READINESS_SCHEMA_VERSION}`,
        "artifact_type: spec_planning_readiness",
        `spec_id: ${yamlScalar(input.specification.specId)}`,
        `planning_readiness: ${input.planningReadiness}`,
        `spec_revision: ${yamlScalar(input.specification.specRevision)}`
    ];
    if (input.review !== null) {
        lines.push("review:", `  id: ${yamlScalar(input.review.id)}`, `  ref: ${yamlScalar(input.review.ref)}`, `  digest: ${yamlScalar(input.review.digest)}`, `  protocol_version: ${input.review.protocolVersion}`, `  reviewed_at: ${yamlScalar(input.review.reviewedAt)}`, `  reviewed_by: ${yamlScalar(input.review.reviewedBy)}`, `recommended_workflow_level: ${input.review.recommendedWorkflowLevel}`);
    }
    if (input.waiver !== null) {
        lines.push("waiver:", `  waiver_id: ${yamlScalar(input.waiver.waiver_id)}`, "  waiver_type: planning-readiness", `  subject_id: ${yamlScalar(input.waiver.subject_id)}`, `  attempt_id: ${yamlNullable(input.waiver.attempt_id)}`, `  reason: ${yamlScalar(input.waiver.reason)}`, `  recorded_by: ${yamlScalar(input.waiver.recorded_by)}`, `  recorded_at: ${yamlScalar(input.waiver.recorded_at)}`, `  expires_at: ${yamlNullable(input.waiver.expires_at)}`, `  authority_reference: ${yamlNullable(input.waiver.authority_reference)}`, `  status: ${input.waiver.status}`);
    }
    lines.push(`recorded_at: ${yamlScalar(input.recordedAt)}`, `recorded_by: ${yamlScalar(input.recordedBy)}`);
    if (input.reason !== undefined)
        lines.push(`reason: ${yamlScalar(input.reason)}`);
    lines.push("---", "", "# Specification Planning Readiness", "", `Planning readiness is **${input.planningReadiness}** for specification revision \`${input.specification.specRevision}\`.`, "");
    return lines.join("\n");
}
function addWritePreconditions(preconditions, target) {
    preconditions.push((0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(target));
    if (target.exists)
        preconditions.push((0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(target));
}
function toExpectedCondition(precondition) {
    return {
        path: precondition.repositoryRelativePath,
        kind: precondition.kind,
        expectedState: precondition.kind === "content-revision"
            ? precondition.expectedRevision
            : precondition.expectedPresence
    };
}
function yamlScalar(value) {
    return JSON.stringify(value);
}
function yamlNullable(value) {
    return value === undefined || value === null ? "null" : yamlScalar(value);
}
