"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.collectManifestMarkerEvidence = collectManifestMarkerEvidence;
exports.collectLocalReleaseMetadataMarkerEvidence = collectLocalReleaseMetadataMarkerEvidence;
exports.collectReleaseTagMarkerEvidence = collectReleaseTagMarkerEvidence;
exports.normalizeReleaseTagVersion = normalizeReleaseTagVersion;
exports.readJsonRecord = readJsonRecord;
exports.isRecord = isRecord;
exports.isReleaseNotesSourceSummaryLike = isReleaseNotesSourceSummaryLike;
exports.collectMarkdownFiles = collectMarkdownFiles;
exports.readPlanningArtifact = readPlanningArtifact;
exports.readRenderedSource = readRenderedSource;
exports.groupRenderedSources = groupRenderedSources;
exports.createPlanningGroupLabel = createPlanningGroupLabel;
exports.appendEvidenceSection = appendEvidenceSection;
exports.extractEvidenceLines = extractEvidenceLines;
exports.extractCompatibilityEvidenceLines = extractCompatibilityEvidenceLines;
exports.extractMarkdownSectionLines = extractMarkdownSectionLines;
exports.collectMarkdownSections = collectMarkdownSections;
exports.normalizeEvidenceLines = normalizeEvidenceLines;
exports.isPrivateLicenseOperationReleaseNoteSource = isPrivateLicenseOperationReleaseNoteSource;
exports.redactPrivateLicenseOperationReleaseNoteTitle = redactPrivateLicenseOperationReleaseNoteTitle;
exports.redactPrivateLicenseOperationReleaseNoteLines = redactPrivateLicenseOperationReleaseNoteLines;
exports.containsPrivateLicenseOperationText = containsPrivateLicenseOperationText;
exports.normalizeRelativePath = normalizeRelativePath;
exports.toRepositoryRelativePath = toRepositoryRelativePath;
exports.requireStableVersion = requireStableVersion;
exports.compareStableVersions = compareStableVersions;
exports.compareParsedVersions = compareParsedVersions;
exports.compareMarkerEvidence = compareMarkerEvidence;
exports.comparePlanningSources = comparePlanningSources;
exports.comparePlanningExclusions = comparePlanningExclusions;
exports.compareRenderedSources = compareRenderedSources;
// Responsibility-focused extraction from release-notes.ts.
const node_child_process_1 = require("node:child_process");
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const cli_constants_1 = require("../../../lib/config/cli-constants");
const errors_1 = require("../../../lib/errors");
const version_1 = require("./version");
const release_notes_contracts_1 = require("./release-notes-contracts");
function collectManifestMarkerEvidence(options, currentVersion) {
    if (!node_fs_1.default.existsSync(options.releaseRoot) || !node_fs_1.default.statSync(options.releaseRoot).isDirectory()) {
        return [];
    }
    return node_fs_1.default.readdirSync(options.releaseRoot, { withFileTypes: true })
        .filter((entry) => entry.isDirectory())
        .flatMap((entry) => {
        const bundledManifestPath = node_path_1.default.join(options.releaseRoot, entry.name, release_notes_contracts_1.RELEASE_DOWNLOAD_BUNDLE_DIRECTORY, cli_constants_1.RELEASE_MANIFEST_FILENAME);
        const bundledManifestPathRelative = `${options.releaseRootRelative}/${entry.name}/${release_notes_contracts_1.RELEASE_DOWNLOAD_BUNDLE_DIRECTORY}/${cli_constants_1.RELEASE_MANIFEST_FILENAME}`;
        const rootManifestPath = node_path_1.default.join(options.releaseRoot, entry.name, cli_constants_1.RELEASE_MANIFEST_FILENAME);
        const rootManifestPathRelative = `${options.releaseRootRelative}/${entry.name}/${cli_constants_1.RELEASE_MANIFEST_FILENAME}`;
        const manifestPath = node_fs_1.default.existsSync(bundledManifestPath) ? bundledManifestPath : rootManifestPath;
        const manifestPathRelative = node_fs_1.default.existsSync(bundledManifestPath) ? bundledManifestPathRelative : rootManifestPathRelative;
        if (!node_fs_1.default.existsSync(manifestPath) || !node_fs_1.default.statSync(manifestPath).isFile()) {
            return [];
        }
        const manifest = readJsonRecord(manifestPath);
        const version = typeof manifest.version === "string" ? manifest.version : entry.name;
        const parsed = (0, version_1.parseReleaseVersion)(version);
        if (!parsed.ok || compareParsedVersions(parsed, currentVersion) >= 0) {
            return [];
        }
        return [{
                source: "published-manifest",
                version: parsed.version,
                path: manifestPathRelative
            }];
    })
        .sort(compareMarkerEvidence);
}
function collectLocalReleaseMetadataMarkerEvidence(options, currentVersion) {
    if (!node_fs_1.default.existsSync(options.releaseRoot) || !node_fs_1.default.statSync(options.releaseRoot).isDirectory()) {
        return [];
    }
    return node_fs_1.default.readdirSync(options.releaseRoot, { withFileTypes: true })
        .filter((entry) => entry.isDirectory())
        .flatMap((entry) => {
        const metadataPath = node_path_1.default.join(options.releaseRoot, entry.name, "staging", ".day-shift-release.json");
        const metadataPathRelative = `${options.releaseRootRelative}/${entry.name}/staging/.day-shift-release.json`;
        if (!node_fs_1.default.existsSync(metadataPath) || !node_fs_1.default.statSync(metadataPath).isFile()) {
            return [];
        }
        const metadata = readJsonRecord(metadataPath);
        const parsed = (0, version_1.parseReleaseVersion)(metadata.version);
        if (!parsed.ok || compareParsedVersions(parsed, currentVersion) >= 0) {
            return [];
        }
        return [{
                source: "local-release-metadata",
                version: parsed.version,
                path: metadataPathRelative
            }];
    })
        .sort(compareMarkerEvidence);
}
function collectReleaseTagMarkerEvidence(options, currentVersion) {
    let tags;
    try {
        tags = (0, node_child_process_1.execFileSync)("git", ["tag", "--list"], {
            cwd: options.repositoryRoot,
            encoding: "utf8",
            stdio: ["ignore", "pipe", "ignore"]
        })
            .split(/\r?\n/)
            .map((tag) => tag.trim())
            .filter((tag) => tag.length > 0);
    }
    catch {
        return [];
    }
    return tags
        .flatMap((tag) => {
        const version = normalizeReleaseTagVersion(tag);
        if (version === null) {
            return [];
        }
        const parsed = (0, version_1.parseReleaseVersion)(version);
        if (!parsed.ok || compareParsedVersions(parsed, currentVersion) >= 0) {
            return [];
        }
        return [{
                source: "release-tag",
                version: parsed.version,
                path: `tag:${tag}`
            }];
    })
        .sort(compareMarkerEvidence);
}
function normalizeReleaseTagVersion(tag) {
    for (const pattern of [/^v(\d+\.\d+\.\d+)$/, /^release-(\d+\.\d+\.\d+)$/, /^day-shift-v(\d+\.\d+\.\d+)$/]) {
        const match = pattern.exec(tag);
        if (match !== null) {
            return match[1];
        }
    }
    return null;
}
function readJsonRecord(filePath) {
    try {
        const parsed = JSON.parse(node_fs_1.default.readFileSync(filePath, "utf8"));
        return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
            ? parsed
            : {};
    }
    catch {
        return {};
    }
}
function isRecord(value) {
    return typeof value === "object" && value !== null && !Array.isArray(value);
}
function isReleaseNotesSourceSummaryLike(value) {
    if (!isRecord(value) || !Array.isArray(value.selectedSources)) {
        return false;
    }
    return value.selectedSources.every((source) => isRecord(source) && typeof source.path === "string");
}
function collectMarkdownFiles(directory) {
    if (!node_fs_1.default.existsSync(directory) || !node_fs_1.default.statSync(directory).isDirectory()) {
        return [];
    }
    return node_fs_1.default.readdirSync(directory, { withFileTypes: true })
        .flatMap((entry) => {
        const entryPath = node_path_1.default.join(directory, entry.name);
        if (entry.isDirectory()) {
            return collectMarkdownFiles(entryPath);
        }
        return entry.isFile() && entry.name.endsWith(".md") ? [entryPath] : [];
    })
        .sort();
}
function readPlanningArtifact(filePath) {
    const content = node_fs_1.default.readFileSync(filePath, "utf8");
    const metadata = {};
    const frontMatter = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
    if (frontMatter !== null) {
        for (const line of frontMatter[1].split(/\r?\n/)) {
            const match = /^([A-Za-z0-9_-]+):\s*"?([^"#]+?)"?\s*$/.exec(line);
            if (match !== null) {
                metadata[match[1]] = match[2].trim();
            }
        }
    }
    return {
        metadata,
        title: /^#\s+(.+)$/m.exec(content)?.[1].trim() ?? null
    };
}
function readRenderedSource(repositoryRoot, source) {
    const filePath = node_path_1.default.join(repositoryRoot, source.path);
    const artifact = readPlanningArtifact(filePath);
    const content = node_fs_1.default.readFileSync(filePath, "utf8");
    return {
        ...source,
        title: redactPrivateLicenseOperationReleaseNoteTitle(source.title ?? artifact.title),
        metadata: artifact.metadata,
        summary: redactPrivateLicenseOperationReleaseNoteLines(extractEvidenceLines(content, ["Summary", "Review Status", "Milestone Intent"])),
        behavior: redactPrivateLicenseOperationReleaseNoteLines(extractEvidenceLines(content, ["Acceptance Criteria Results", "Acceptance Criteria Review"])),
        validation: redactPrivateLicenseOperationReleaseNoteLines(extractEvidenceLines(content, ["Validation Performed", "Validation Review"])),
        followUps: redactPrivateLicenseOperationReleaseNoteLines(extractEvidenceLines(content, ["Discovered Work", "Risks and Follow-Ups", "Follow-Up Tasks", "Backlog Work", "Accepted Residual Work"])),
        compatibility: redactPrivateLicenseOperationReleaseNoteLines(extractCompatibilityEvidenceLines(content))
    };
}
function groupRenderedSources(sources) {
    const groups = new Map();
    for (const source of sources) {
        const label = createPlanningGroupLabel(source.metadata);
        groups.set(label, [...(groups.get(label) ?? []), source]);
    }
    return Array.from(groups.entries())
        .map(([label, groupSources]) => ({
        label,
        sources: groupSources.sort(compareRenderedSources)
    }))
        .sort((left, right) => left.label.localeCompare(right.label));
}
function createPlanningGroupLabel(metadata) {
    const parts = [metadata.slice, metadata.phase, metadata.milestone]
        .filter((value) => typeof value === "string" && value.length > 0);
    return parts.length === 0 ? "Planning Evidence" : parts.join(" / ");
}
function appendEvidenceSection(lines, title, sources, readItems) {
    const rows = sources
        .flatMap((source) => readItems(source).map((item) => ({
        source,
        item
    })))
        .filter((row) => row.item.length > 0);
    if (rows.length === 0) {
        return;
    }
    lines.push(`## ${title}`);
    lines.push("");
    for (const row of rows) {
        lines.push(`- ${row.item}`);
        lines.push(`  - Source: ${row.source.path}`);
    }
    lines.push("");
}
function extractEvidenceLines(content, headings) {
    return headings.flatMap((heading) => extractMarkdownSectionLines(content, heading));
}
function extractCompatibilityEvidenceLines(content) {
    const sections = collectMarkdownSections(content)
        .filter((section) => /compatibility|migration|schema/i.test(section.heading));
    return normalizeEvidenceLines(sections.flatMap((section) => section.lines));
}
function extractMarkdownSectionLines(content, heading) {
    const section = collectMarkdownSections(content)
        .find((candidate) => candidate.heading.toLowerCase() === heading.toLowerCase());
    return section === undefined ? [] : normalizeEvidenceLines(section.lines);
}
function collectMarkdownSections(content) {
    const sections = [];
    let current = null;
    for (const line of content.split(/\r?\n/)) {
        const headingMatch = /^##\s+(.+?)\s*$/.exec(line);
        if (headingMatch !== null) {
            current = {
                heading: headingMatch[1].trim(),
                lines: []
            };
            sections.push(current);
            continue;
        }
        if (current !== null) {
            current.lines.push(line);
        }
    }
    return sections;
}
function normalizeEvidenceLines(lines) {
    return lines
        .map((line) => line.trim())
        .filter((line) => line.length > 0)
        .filter((line) => !/^[-*]\s*(none|none currently|not applicable)\.?$/i.test(line))
        .map((line) => line.replace(/^[-*]\s+/, "").trim())
        .filter((line) => line.length > 0);
}
function isPrivateLicenseOperationReleaseNoteSource(artifactPath) {
    return release_notes_contracts_1.PRIVATE_LICENSE_OPERATION_SOURCE_PATH_PATTERN.test(artifactPath);
}
function redactPrivateLicenseOperationReleaseNoteTitle(value) {
    if (value === null) {
        return null;
    }
    return containsPrivateLicenseOperationText(value)
        ? release_notes_contracts_1.PRIVATE_LICENSE_OPERATION_RELEASE_NOTE_TITLE
        : value;
}
function redactPrivateLicenseOperationReleaseNoteLines(lines) {
    const redactedLines = [];
    let redactionAdded = false;
    for (const line of lines) {
        if (containsPrivateLicenseOperationText(line)) {
            if (!redactionAdded) {
                redactedLines.push(release_notes_contracts_1.PRIVATE_LICENSE_OPERATION_RELEASE_NOTE_REDACTION);
                redactionAdded = true;
            }
            continue;
        }
        redactedLines.push(line);
    }
    return redactedLines;
}
function containsPrivateLicenseOperationText(value) {
    return release_notes_contracts_1.PRIVATE_LICENSE_OPERATION_TEXT_PATTERNS.some((pattern) => pattern.test(value));
}
function normalizeRelativePath(value) {
    return value.trim().replace(/\\/g, "/").replace(/^\.?\//, "");
}
function toRepositoryRelativePath(repositoryRoot, filePath) {
    return node_path_1.default.relative(repositoryRoot, filePath).split(node_path_1.default.sep).join("/");
}
function requireStableVersion(version, label) {
    const parsed = (0, version_1.parseReleaseVersion)(version);
    if (!parsed.ok) {
        throw (0, errors_1.createUsageError)(`Release notes marker resolution requires a stable ${label}.`, [
            `Reason: ${parsed.reason}`,
            `Version: ${version}`,
            `Recovery: ${parsed.correctiveAction}`
        ]);
    }
    return parsed;
}
function compareStableVersions(left, right) {
    return compareParsedVersions(requireStableVersion(left, "version"), requireStableVersion(right, "version"));
}
function compareParsedVersions(left, right) {
    return left.major - right.major ||
        left.minor - right.minor ||
        left.patch - right.patch;
}
function compareMarkerEvidence(left, right) {
    return compareStableVersions(left.version, right.version) ||
        left.source.localeCompare(right.source) ||
        String(left.path ?? "").localeCompare(String(right.path ?? ""));
}
function comparePlanningSources(left, right) {
    return left.path.localeCompare(right.path) || left.kind.localeCompare(right.kind);
}
function comparePlanningExclusions(left, right) {
    return left.path.localeCompare(right.path) || left.reason.localeCompare(right.reason);
}
function compareRenderedSources(left, right) {
    return createPlanningGroupLabel(left.metadata).localeCompare(createPlanningGroupLabel(right.metadata)) ||
        left.path.localeCompare(right.path) ||
        left.kind.localeCompare(right.kind);
}
