"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveAcceptedPredecessorTargets = resolveAcceptedPredecessorTargets;
exports.readDeclaredPredecessorTaskPaths = readDeclaredPredecessorTaskPaths;
exports.readAcceptedPredecessorSource = readAcceptedPredecessorSource;
exports.qualifyAcceptedPredecessorTarget = qualifyAcceptedPredecessorTarget;
exports.inspectAcceptedPredecessorCandidate = inspectAcceptedPredecessorCandidate;
exports.inspectTarget = inspectTarget;
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 planning_document_utils_1 = require("../planning-document-utils");
const semantic_evidence_1 = require("../semantic-evidence");
const task_lifecycle_1 = require("../task-lifecycle");
const task_validation_1 = require("../task-validation");
const implementation_summary_reconciliation_1 = require("../implementation-summary-reconciliation");
const baseline_planning_1 = require("./baseline-planning");
const contracts_1 = require("./contracts");
const repository_support_1 = require("./repository-support");
const target_inspection_1 = require("./target-inspection");
function resolveAcceptedPredecessorTargets(options) {
    const declaredSources = readDeclaredPredecessorTaskPaths(options.currentTaskDefinitionPath, options.currentTaskText);
    const allSourcePaths = (0, repository_support_1.unique)([...declaredSources, ...options.explicitlySelectedSources.values()]);
    const sources = new Map(allSourcePaths.map((sourcePath) => [sourcePath, readAcceptedPredecessorSource(options.repositoryRoot, sourcePath)]));
    const resolved = new Map();
    for (const target of options.targets) {
        if (!target.dirty || target.contentSha256 === null || target.preExistingClassification === 'adopted-pre-staged') {
            continue;
        }
        const explicitSource = options.explicitlySelectedSources.get(target.path) ?? null;
        const candidatePaths = explicitSource === null ? declaredSources : [explicitSource];
        const candidates = candidatePaths.flatMap((sourcePath) => {
            const source = sources.get(sourcePath) ?? null;
            if (source === null)
                return [];
            const provenance = qualifyAcceptedPredecessorTarget(source, target);
            return provenance === null ? [] : [provenance];
        });
        if (explicitSource !== null && candidates.length !== 1) {
            const inspected = inspectAcceptedPredecessorCandidate({
                repositoryRoot: options.repositoryRoot,
                sourceTaskDefinitionPath: explicitSource,
                target,
            });
            throw (0, errors_1.createUsageError)(`Accepted predecessor recovery source '${explicitSource}' does not provide one current exact digest match for '${target.path}'.`, [
                ...inspected.mismatchReasons,
                `Exact matching remains required and was not weakened for '${target.path}'.`,
                `Ordinary adoption is a separate explicit recovery: --adopt '${target.path}::<concrete ownership rationale>'.`,
            ]);
        }
        if (candidates.length === 1)
            resolved.set(target.path, candidates[0]);
    }
    return resolved;
}
function readDeclaredPredecessorTaskPaths(currentTaskDefinitionPath, currentTaskText) {
    return (0, repository_support_1.unique)((0, semantic_evidence_1.readChangedPaths)((0, planning_document_utils_1.parseMarkdownSections)(currentTaskText).get('Dependencies') ?? '')
        .filter((candidate) => candidate.endsWith('/task-definition.md'))
        .filter((candidate) => candidate !== currentTaskDefinitionPath));
}
function readAcceptedPredecessorSource(repositoryRoot, sourceTaskDefinitionPath) {
    let taskDefinitionPath;
    try {
        taskDefinitionPath = (0, paths_1.parseRepositoryRelativePath)(sourceTaskDefinitionPath).normalizedPath;
    }
    catch {
        return null;
    }
    const taskAbsolute = node_path_1.default.join(repositoryRoot, taskDefinitionPath);
    const implementationSummaryPath = node_path_1.default.posix.join(node_path_1.default.posix.dirname(taskDefinitionPath), 'implementation-summary.md');
    const summaryAbsolute = node_path_1.default.join(repositoryRoot, implementationSummaryPath);
    if (!node_fs_1.default.existsSync(taskAbsolute) || !node_fs_1.default.existsSync(summaryAbsolute))
        return null;
    const taskText = node_fs_1.default.readFileSync(taskAbsolute, 'utf8');
    const summaryText = node_fs_1.default.readFileSync(summaryAbsolute, 'utf8');
    const pair = (0, task_lifecycle_1.projectTaskLifecyclePair)({
        taskDefinition: taskText,
        implementationSummary: summaryText,
    });
    const attempt = pair.summary?.currentAttempt ?? null;
    if (pair.blockingFindings.length > 0 ||
        !pair.terminal ||
        !pair.acceptedCompleted ||
        pair.task.status !== 'completed' ||
        pair.task.readiness !== 'completed' ||
        pair.summary?.status !== 'completed' ||
        attempt?.attemptId === null ||
        attempt?.attemptId === undefined ||
        attempt.implementationStatus !== 'completed' ||
        (attempt.reviewDisposition !== 'accepted' && attempt.reviewDisposition !== 'accepted_with_follow_up')) {
        return null;
    }
    const review = (0, implementation_summary_reconciliation_1.reviewImplementationSummary)(repositoryRoot, {
        taskDefinitionPath,
    });
    const receipt = review.reviewReceipt;
    if (review.closeoutEvidenceStatus !== 'sufficient' ||
        review.blockingIssues.length > 0 ||
        receipt === null ||
        receipt.attemptId !== attempt.attemptId ||
        (receipt.reviewDisposition !== 'accepted' && receipt.reviewDisposition !== 'accepted_with_follow_up') ||
        receipt.blockerCount !== 0) {
        return null;
    }
    const taskId = pair.task.taskId;
    if (taskId === null)
        return null;
    const attemptValidations = (0, task_validation_1.readTaskValidationResults)(implementationSummaryPath, summaryText).filter((validation) => validation.attemptId === attempt.attemptId);
    const identities = (0, task_validation_1.projectTaskValidationIdentities)(attemptValidations);
    const effectiveIds = new Set(identities.effectiveValidationIds);
    return {
        taskId,
        taskDefinitionPath,
        implementationSummaryPath,
        attemptId: attempt.attemptId,
        reviewReceiptId: receipt.reviewReceiptId,
        implementationSummaryRevision: receipt.implementationSummaryRevision,
        changedPaths: new Set((0, semantic_evidence_1.readChangedPaths)((0, planning_document_utils_1.parseMarkdownSections)(summaryText).get('Changed Paths') ?? '')),
        baseline: (0, baseline_planning_1.readAttemptRuntimeBaseline)(implementationSummaryPath, summaryText, attempt.attemptId),
        validations: attemptValidations.filter((validation) => effectiveIds.has(validation.validationId)),
    };
}
function qualifyAcceptedPredecessorTarget(source, target) {
    if (!source.changedPaths.has(target.path) || target.contentSha256 === null)
        return null;
    const sourceRevisions = [];
    const baselineTarget = source.baseline?.declaredTargets.find((entry) => entry.path === target.path);
    if (baselineTarget !== undefined &&
        (baselineTarget.preExistingClassification === 'adopted-pre-staged' ||
            baselineTarget.preExistingClassification === 'accepted-predecessor') &&
        baselineTarget.contentSha256 === target.contentSha256 &&
        source.baseline !== null) {
        sourceRevisions.push(source.baseline.sourceRevision);
    }
    const observedValidations = source.validations.filter((validation) => validation.status === 'passed' &&
        validation.observationsComplete &&
        validation.observations.some((observation) => observation.path === target.path));
    const observations = observedValidations.flatMap((validation) => validation.observations
        .filter((observation) => observation.path === target.path)
        .map((observation) => ({
        digest: observation.contentSha256,
        sourceRevision: validation.sourceRevision,
    })));
    if (observations.length > 0 && observations.every((observation) => observation.digest === target.contentSha256)) {
        sourceRevisions.push(...observations.map((observation) => observation.sourceRevision));
    }
    const exactRevisions = (0, repository_support_1.unique)(sourceRevisions).filter((revision) => contracts_1.SOURCE_REVISION_PATTERN.test(revision));
    if (exactRevisions.length !== 1)
        return null;
    return {
        taskId: source.taskId,
        taskDefinitionPath: source.taskDefinitionPath,
        implementationSummaryPath: source.implementationSummaryPath,
        attemptId: source.attemptId,
        reviewReceiptId: source.reviewReceiptId,
        implementationSummaryRevision: source.implementationSummaryRevision,
        pathDigest: target.contentSha256,
        sourceRevision: exactRevisions[0],
    };
}
function inspectAcceptedPredecessorCandidate(options) {
    const taskDefinitionPath = options.sourceTaskDefinitionPath;
    const implementationSummaryPath = node_path_1.default.posix.join(node_path_1.default.posix.dirname(taskDefinitionPath), 'implementation-summary.md');
    const taskExists = node_fs_1.default.existsSync(node_path_1.default.join(options.repositoryRoot, taskDefinitionPath));
    const summaryExists = node_fs_1.default.existsSync(node_path_1.default.join(options.repositoryRoot, implementationSummaryPath));
    if (!taskExists || !summaryExists) {
        return {
            taskDefinitionPath,
            implementationSummaryPath,
            taskId: null,
            terminalAttemptId: null,
            current: false,
            exactDigestMatch: false,
            targetContentSha256: options.target.contentSha256,
            digestEvidence: [],
            mismatchReasons: [
                !taskExists
                    ? `Accepted predecessor task definition '${taskDefinitionPath}' does not exist.`
                    : `Accepted predecessor implementation summary '${implementationSummaryPath}' does not exist.`,
            ],
            provenance: null,
        };
    }
    let source;
    try {
        source = readAcceptedPredecessorSource(options.repositoryRoot, taskDefinitionPath);
    }
    catch (error) {
        return {
            taskDefinitionPath,
            implementationSummaryPath,
            taskId: null,
            terminalAttemptId: null,
            current: false,
            exactDigestMatch: false,
            targetContentSha256: options.target.contentSha256,
            digestEvidence: [],
            mismatchReasons: [(0, target_inspection_1.errorMessage)(error)],
            provenance: null,
        };
    }
    if (source === null) {
        return {
            taskDefinitionPath,
            implementationSummaryPath,
            taskId: null,
            terminalAttemptId: null,
            current: false,
            exactDigestMatch: false,
            targetContentSha256: options.target.contentSha256,
            digestEvidence: [],
            mismatchReasons: [
                `Accepted predecessor '${taskDefinitionPath}' is not a current terminal completed task with accepted review evidence.`,
            ],
            provenance: null,
        };
    }
    const digestEvidence = [];
    const baselineTarget = source.baseline?.declaredTargets.find((entry) => entry.path === options.target.path);
    if (baselineTarget !== undefined &&
        (baselineTarget.preExistingClassification === 'adopted-pre-staged' ||
            baselineTarget.preExistingClassification === 'accepted-predecessor')) {
        digestEvidence.push({
            source: 'baseline',
            contentSha256: baselineTarget.contentSha256,
            sourceRevision: source.baseline?.sourceRevision ?? null,
        });
    }
    for (const validation of source.validations) {
        if (validation.status !== 'passed' || !validation.observationsComplete)
            continue;
        for (const observation of validation.observations) {
            if (observation.path !== options.target.path)
                continue;
            digestEvidence.push({
                source: 'validation',
                contentSha256: observation.contentSha256,
                sourceRevision: validation.sourceRevision,
            });
        }
    }
    const provenance = qualifyAcceptedPredecessorTarget(source, options.target);
    const mismatchReasons = [];
    if (!source.changedPaths.has(options.target.path)) {
        mismatchReasons.push(`Accepted predecessor '${taskDefinitionPath}' does not record '${options.target.path}' in Changed Paths.`);
    }
    if (options.target.contentSha256 === null) {
        mismatchReasons.push(`Current target '${options.target.path}' has no content digest to match.`);
    }
    else {
        const observedDigests = (0, repository_support_1.unique)(digestEvidence.map((entry) => entry.contentSha256).filter((entry) => entry !== null));
        if (!observedDigests.includes(options.target.contentSha256)) {
            mismatchReasons.push(`Accepted predecessor digest mismatch for '${options.target.path}': current ${options.target.contentSha256}; observed ${observedDigests.length === 0 ? 'none' : observedDigests.join(', ')}.`);
        }
        const matchingRevisions = (0, repository_support_1.unique)(digestEvidence
            .filter((entry) => entry.contentSha256 === options.target.contentSha256)
            .map((entry) => entry.sourceRevision)
            .filter((entry) => entry !== null && contracts_1.SOURCE_REVISION_PATTERN.test(entry)));
        if (observedDigests.includes(options.target.contentSha256) && matchingRevisions.length !== 1) {
            mismatchReasons.push(`Accepted predecessor matching digest for '${options.target.path}' must bind to exactly one source revision; observed ${matchingRevisions.length}.`);
        }
    }
    return {
        taskDefinitionPath: source.taskDefinitionPath,
        implementationSummaryPath: source.implementationSummaryPath,
        taskId: source.taskId,
        terminalAttemptId: source.attemptId,
        current: true,
        exactDigestMatch: provenance !== null,
        targetContentSha256: options.target.contentSha256,
        digestEvidence,
        mismatchReasons: provenance === null ? mismatchReasons : [],
        provenance,
    };
}
function inspectTarget(repositoryRoot, targetPath, adoptionRationale) {
    const absolutePath = node_path_1.default.join(repositoryRoot, targetPath);
    const status = (0, repository_support_1.runGit)(repositoryRoot, ['status', '--porcelain=v1', '--untracked-files=all', '--', targetPath]);
    if (status === null) {
        throw (0, errors_1.createUsageError)(`Unable to inspect Git dirty state for declared target '${targetPath}'.`);
    }
    const dirty = status !== '';
    if (adoptionRationale !== null && !dirty) {
        throw (0, errors_1.createUsageError)(`Adoption path '${targetPath}' is not dirty at baseline capture.`);
    }
    let exists = false;
    let kind = 'absent';
    let contentSha256 = null;
    try {
        const stat = node_fs_1.default.lstatSync(absolutePath);
        if (stat.isSymbolicLink()) {
            throw (0, errors_1.createUsageError)(`Declared target '${targetPath}' is a symbolic link; baseline hashing requires a bounded file or directory.`);
        }
        exists = true;
        if (stat.isFile()) {
            kind = 'file';
            contentSha256 = (0, target_inspection_1.hashFile)(absolutePath);
        }
        else if (stat.isDirectory()) {
            kind = 'directory';
            contentSha256 = (0, target_inspection_1.hashDirectory)(absolutePath);
        }
        else {
            throw (0, errors_1.createUsageError)(`Declared target '${targetPath}' is neither a regular file nor directory.`);
        }
    }
    catch (error) {
        if (error.code !== 'ENOENT')
            throw error;
    }
    const visibility = (0, target_inspection_1.inspectRepositoryVisibility)(repositoryRoot, targetPath, exists);
    return {
        path: targetPath,
        exists,
        kind,
        contentSha256,
        repositoryVisibility: visibility.state,
        ignoreRule: visibility.ignoreRule,
        dirty,
        preExistingClassification: adoptionRationale !== null ? 'adopted-pre-staged' : dirty ? 'pre-existing-unattributed' : 'clean',
        adoptionRationale: adoptionRationale ?? '',
        acceptedPredecessor: null,
    };
}
