"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.IMPACT_BODY_SECTIONS = exports.IMPACT_METADATA_FIELDS = exports.IMPACT_ARTIFACT_FAMILIES = void 0;
exports.getImpactInputContract = getImpactInputContract;
exports.readImpactArtifactInputEvidence = readImpactArtifactInputEvidence;
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 paths_1 = require("../paths");
exports.IMPACT_ARTIFACT_FAMILIES = [
    "specification",
    "slice_overview",
    "phase_overview",
    "milestone_overview",
    "task_definition",
    "implementation_summary",
    "reconciliation"
];
exports.IMPACT_METADATA_FIELDS = [
    "artifact_type",
    "slice",
    "phase",
    "milestone",
    "task",
    "planning_depth",
    "status",
    "readiness",
    "implementation_status",
    "reconciliation_status",
    "upstream.specs",
    "upstream.slice_overview",
    "upstream.phase_overview",
    "upstream.milestone_overview",
    "upstream.task_definition",
    "artifact_path"
];
exports.IMPACT_BODY_SECTIONS = {
    slice_overview: ["Phases"],
    phase_overview: ["Milestones"],
    milestone_overview: ["Tasks"],
    task_definition: ["Implementation Target Paths"],
    implementation_summary: ["Changed Paths", "Acceptance Criteria Results", "Validation Performed"],
    reconciliation: [
        "Completed Task Summaries",
        "Acceptance Criteria Review",
        "Planned Work",
        "Discovered Work",
        "Backlog Work",
        "Accepted Residual Work",
        "Validation Review",
        "Follow-Up Tasks",
        "Review Concerns",
        "Final Notes"
    ],
    specification: []
};
function getImpactInputContract() {
    return {
        artifactFamilies: [...exports.IMPACT_ARTIFACT_FAMILIES],
        metadataFields: [...exports.IMPACT_METADATA_FIELDS],
        bodySectionsByFamily: {
            specification: [...exports.IMPACT_BODY_SECTIONS.specification],
            slice_overview: [...exports.IMPACT_BODY_SECTIONS.slice_overview],
            phase_overview: [...exports.IMPACT_BODY_SECTIONS.phase_overview],
            milestone_overview: [...exports.IMPACT_BODY_SECTIONS.milestone_overview],
            task_definition: [...exports.IMPACT_BODY_SECTIONS.task_definition],
            implementation_summary: [...exports.IMPACT_BODY_SECTIONS.implementation_summary],
            reconciliation: [...exports.IMPACT_BODY_SECTIONS.reconciliation]
        },
        proseBoundary: "Arbitrary planning prose remains contextual evidence unless the section is explicitly named by this contract and parsed by that section's extraction rule.",
        missingEvidenceBoundary: "Missing, placeholder, stale, unreadable, malformed, or contradictory artifact evidence is preserved for downstream impact findings instead of being dropped.",
        noWriteBoundary: "Impact input collection is local and read-only; it does not format final findings, inspect Git state, repair artifacts, synchronize metadata, mutate planning files, or generate artifacts.",
        readOnly: true
    };
}
function readImpactArtifactInputEvidence(options) {
    const artifactPath = normalizeArtifactPath(options.artifactPath);
    const markdownResult = readArtifactMarkdown(options, artifactPath);
    if (markdownResult.ok === false) {
        return {
            artifactPath,
            artifactFamily: artifactFamilyFromPath(artifactPath) ?? "unsupported",
            artifactType: null,
            readState: "unreadable",
            metadataEvidence: [
                {
                    state: "unreadable",
                    sourceArtifactPath: artifactPath,
                    field: "artifact_path",
                    rawText: artifactPath,
                    value: artifactPath,
                    message: markdownResult.message
                }
            ],
            specReferenceEvidence: [],
            bodySectionEvidence: [],
            contextualSectionNames: [],
            errorMessage: markdownResult.message,
            readOnly: true
        };
    }
    const frontMatter = (0, planning_document_utils_1.parseMarkdownFrontMatter)(markdownResult.markdownText);
    const sections = (0, planning_document_utils_1.parseMarkdownSections)(frontMatter.bodyText);
    const artifactType = (0, planning_document_utils_1.readTopLevelField)(frontMatter.frontMatterLines, "artifact_type")?.trim() ?? null;
    const family = resolveImpactArtifactFamily(artifactPath, artifactType);
    const metadataEvidence = readImpactMetadataEvidence(artifactPath, frontMatter.frontMatterLines);
    const specReferenceEvidence = readImpactSpecReferences(artifactPath, frontMatter.frontMatterLines);
    if (family === "unsupported") {
        return {
            artifactPath,
            artifactFamily: "unsupported",
            artifactType,
            readState: "read",
            metadataEvidence,
            specReferenceEvidence,
            bodySectionEvidence: [],
            contextualSectionNames: [...sections.keys()],
            unsupportedReason: `Artifact '${artifactPath}' is not one of the local impact input families.`,
            readOnly: true
        };
    }
    const bodySectionEvidence = readImpactBodySectionEvidence(artifactPath, family, sections);
    const evidenceSectionNames = new Set(bodySectionEvidence.map((entry) => entry.sectionName));
    const contextualSectionNames = [...sections.keys()]
        .filter((sectionName) => !evidenceSectionNames.has(sectionName));
    return {
        artifactPath,
        artifactFamily: family,
        artifactType,
        readState: "read",
        metadataEvidence,
        specReferenceEvidence,
        bodySectionEvidence,
        contextualSectionNames,
        readOnly: true
    };
}
function readArtifactMarkdown(options, artifactPath) {
    if (options.markdownText !== undefined) {
        return { ok: true, markdownText: options.markdownText };
    }
    if (options.repositoryRoot === undefined) {
        return {
            ok: false,
            message: `Artifact '${artifactPath}' could not be read because no repository root or markdown text was supplied.`
        };
    }
    try {
        return {
            ok: true,
            markdownText: node_fs_1.default.readFileSync(node_path_1.default.join(options.repositoryRoot, artifactPath), "utf8")
        };
    }
    catch (error) {
        return {
            ok: false,
            message: `Artifact '${artifactPath}' could not be read: ${error instanceof Error ? error.message : String(error)}.`
        };
    }
}
function normalizeArtifactPath(artifactPath) {
    try {
        return (0, paths_1.parseRepositoryRelativePath)(artifactPath).normalizedPath;
    }
    catch {
        return (0, planning_document_utils_1.toRepositoryLikePath)(artifactPath);
    }
}
function resolveImpactArtifactFamily(artifactPath, artifactType) {
    if (artifactType !== null && isImpactArtifactFamily(artifactType)) {
        return artifactType;
    }
    return artifactFamilyFromPath(artifactPath) ?? "unsupported";
}
function artifactFamilyFromPath(artifactPath) {
    if (/^\.day-shift\/specs\/.+\.md$/.test(artifactPath)) {
        return "specification";
    }
    return null;
}
function isImpactArtifactFamily(value) {
    return exports.IMPACT_ARTIFACT_FAMILIES.includes(value);
}
function readImpactMetadataEvidence(artifactPath, frontMatterLines) {
    const evidence = [
        {
            state: "explicit",
            sourceArtifactPath: artifactPath,
            field: "artifact_path",
            rawText: artifactPath,
            value: artifactPath,
            message: `Artifact path '${artifactPath}' is local repository-relative impact evidence.`
        }
    ];
    for (const field of exports.IMPACT_METADATA_FIELDS) {
        if (field === "artifact_path" || field === "upstream.specs") {
            continue;
        }
        const value = field.startsWith("upstream.")
            ? (0, planning_document_utils_1.readUpstreamField)(frontMatterLines, field.slice("upstream.".length))
            : (0, planning_document_utils_1.readTopLevelField)(frontMatterLines, field);
        if (value === undefined) {
            evidence.push({
                state: "missing",
                sourceArtifactPath: artifactPath,
                field,
                rawText: "",
                message: `Impact metadata field '${field}' is missing from '${artifactPath}'.`
            });
            continue;
        }
        const normalizedValue = value.trim();
        evidence.push({
            state: isPlaceholderValue(normalizedValue) ? "placeholder" : "explicit",
            sourceArtifactPath: artifactPath,
            field,
            rawText: value,
            value: normalizedValue,
            message: `Impact metadata field '${field}' was read from '${artifactPath}'.`
        });
    }
    if (readImpactSpecReferences(artifactPath, frontMatterLines).length === 0) {
        evidence.push({
            state: "missing",
            sourceArtifactPath: artifactPath,
            field: "upstream.specs",
            rawText: "",
            message: `Impact metadata field 'upstream.specs' is missing from '${artifactPath}'.`
        });
    }
    return evidence;
}
function readImpactSpecReferences(artifactPath, frontMatterLines) {
    const specsStart = frontMatterLines.findIndex((line) => /^\s{2}specs:\s*$/.test(line));
    if (specsStart < 0) {
        return [];
    }
    const entries = [];
    let current = null;
    for (let index = specsStart + 1; index < frontMatterLines.length; index += 1) {
        const line = frontMatterLines[index];
        if (/^\S/.test(line) || /^\s{2}[A-Za-z0-9_]+:/.test(line)) {
            break;
        }
        const newEntryMatch = line.match(/^\s{4}-\s+id:\s*(.*)$/);
        if (newEntryMatch !== null) {
            if (current !== null) {
                entries.push(toSpecReferenceEvidence(artifactPath, current));
            }
            current = {
                id: parseSpecScalar(newEntryMatch[1]),
                rawLines: [line]
            };
            continue;
        }
        if (current === null) {
            continue;
        }
        current.rawLines.push(line);
        const fieldMatch = line.match(/^\s{6}([A-Za-z0-9_]+):\s*(.*)$/);
        if (fieldMatch === null) {
            continue;
        }
        const value = parseSpecScalar(fieldMatch[2]);
        if (fieldMatch[1] === "depth") {
            current.depth = value;
        }
        else if (fieldMatch[1] === "ref") {
            current.ref = value;
        }
        else if (fieldMatch[1] === "source_type") {
            current.sourceType = value;
        }
    }
    if (current !== null) {
        entries.push(toSpecReferenceEvidence(artifactPath, current));
    }
    return entries;
}
function toSpecReferenceEvidence(artifactPath, entry) {
    const missingFields = [
        ["id", entry.id],
        ["depth", entry.depth],
        ["ref", entry.ref],
        ["source_type", entry.sourceType]
    ].filter(([, value]) => value === undefined || isPlaceholderValue(String(value)));
    return {
        state: missingFields.length === 0 ? "explicit" : "malformed",
        sourceArtifactPath: artifactPath,
        id: entry.id,
        depth: entry.depth,
        ref: entry.ref,
        sourceType: entry.sourceType,
        rawText: entry.rawLines.join("\n"),
        message: missingFields.length === 0
            ? `Registered source reference '${entry.id}' was read from upstream.specs in '${artifactPath}'.`
            : `Registered source reference in '${artifactPath}' is missing or placeholder evidence for: ${missingFields.map(([field]) => field).join(", ")}.`
    };
}
function readImpactBodySectionEvidence(artifactPath, family, sections) {
    return exports.IMPACT_BODY_SECTIONS[family].map((sectionName) => {
        const rawText = sections.get(sectionName);
        if (rawText === undefined) {
            return {
                state: "missing",
                sourceArtifactPath: artifactPath,
                family,
                sectionName,
                rawText: "",
                extractedPaths: [],
                declaredChildSlugs: [],
                message: `Impact body section '## ${sectionName}' is missing from '${artifactPath}'.`
            };
        }
        const extractedPaths = extractRepositoryRelativePaths(rawText);
        const declaredChildSlugs = sectionName === "Tasks" || sectionName === "Milestones" || sectionName === "Phases"
            ? (0, planning_document_utils_1.readDeclaredChildSlugs)(rawText)
            : [];
        return {
            state: isPlaceholderValue(rawText) ? "placeholder" : "explicit",
            sourceArtifactPath: artifactPath,
            family,
            sectionName,
            rawText,
            extractedPaths,
            declaredChildSlugs,
            message: `Impact body section '## ${sectionName}' was read from '${artifactPath}'.`
        };
    });
}
function extractRepositoryRelativePaths(sectionText) {
    const paths = [];
    const seen = new Set();
    const candidates = [...sectionText.matchAll(/`([^`]+)`/g)].map((match) => match[1].trim());
    for (const candidate of candidates) {
        try {
            const normalizedPath = (0, paths_1.parseRepositoryRelativePath)(candidate).normalizedPath;
            if (seen.has(normalizedPath)) {
                continue;
            }
            seen.add(normalizedPath);
            paths.push(normalizedPath);
        }
        catch {
            continue;
        }
    }
    return paths;
}
function parseSpecScalar(rawValue) {
    const trimmed = rawValue.trim();
    if ((trimmed.startsWith("\"") && trimmed.endsWith("\"")) || (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
        return trimmed.slice(1, -1);
    }
    return trimmed;
}
function isPlaceholderValue(value) {
    const trimmed = value.trim();
    return trimmed === ""
        || /\{\{[^}]+\}\}/.test(trimmed)
        || /^none(?: currently| yet)?\.?$/i.test(trimmed)
        || /^pending\b/i.test(trimmed)
        || /^tbd\.?$/i.test(trimmed)
        || /^todo\b/i.test(trimmed)
        || /^placeholder$/i.test(trimmed);
}
