"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildTaskScopedChangeReport = buildTaskScopedChangeReport;
exports.projectTaskScopedChangeReport = projectTaskScopedChangeReport;
exports.parseGitStatusPorcelainLine = parseGitStatusPorcelainLine;
const changed_paths_1 = require("./changed-paths");
const documentation_path_classifier_1 = require("./documentation-path-classifier");
const diff_scope_comparison_1 = require("./diff-scope-comparison");
const scope_guard_1 = require("./scope-guard");
function buildTaskScopedChangeReport(input) {
    const statusPathEvidence = input.statusLines
        .map(parseGitStatusPorcelainLine)
        .filter((entry) => entry !== null);
    const normalization = (0, changed_paths_1.normalizeChangedPathInputs)(statusPathEvidence.map((entry) => entry.path));
    const comparison = (0, diff_scope_comparison_1.compareChangedPathsToDeclaredScope)({
        changedPathEvidence: normalization.evidence,
        declaredTargetEvidence: input.declaredTargetEvidence
    });
    const scopedChangedPaths = unique(comparison.matchedGroups.flatMap((group) => group.changedPaths));
    const documentationPathClassifications = classifyDocumentationChangedPaths(normalization.normalizedChangedPaths, scopedChangedPaths);
    return {
        statusPathEvidence,
        changedPathEvidence: normalization.evidence,
        normalizedChangedPaths: normalization.normalizedChangedPaths,
        comparison,
        scopedChangedPaths,
        unrelatedChangedPaths: comparison.unmatchedChangedPaths.map((entry) => entry.changedPath),
        pathClassifications: classifyTaskScopedPaths(statusPathEvidence, input.declaredTargetEvidence),
        documentationPathClassifications,
        documentationOnlyChangedPaths: documentationPathClassifications
            .filter((entry) => entry.documentationOnly)
            .map((entry) => entry.path),
        runtimeEligibleChangedPaths: documentationPathClassifications
            .filter((entry) => entry.runtimeEligible)
            .map((entry) => entry.path),
        readOnly: true
    };
}
function projectTaskScopedChangeReport(report, justifiedDeviationPaths) {
    const unrelatedPaths = new Set(report.unrelatedChangedPaths);
    const justified = unique(justifiedDeviationPaths)
        .filter((changedPath) => unrelatedPaths.has(changedPath));
    const unrelatedChangedPathCount = report.unrelatedChangedPaths.length - justified.length;
    return {
        statusPathCount: report.statusPathEvidence.length,
        declaredTargetChangedPaths: report.scopedChangedPaths,
        justifiedDeviationChangedPaths: justified,
        unrelatedChangedPathCount,
        invalidChangedPathEvidenceCount: report.comparison.invalidChangedPathEvidence.length,
        classifications: {
            declaredTarget: report.scopedChangedPaths.length,
            justifiedDeviation: justified.length,
            unrelated: unrelatedChangedPathCount
        },
        unrelatedChangedPathsOmitted: true,
        safeContinuationGuidance: unrelatedChangedPathCount === 0
            ? "No unrelated dirty-worktree paths were detected."
            : "Continue with the selected task using declared-target and justified-deviation evidence; unrelated dirty-worktree paths are counted but are not attributed to this task.",
        explicitAuditGuidance: "Run `git status --short` as a separate explicit repository audit when unrelated path details are required; implementation-summary build omits those details by default.",
        readOnly: true
    };
}
function parseGitStatusPorcelainLine(line) {
    if (line.length < 4) {
        return null;
    }
    const statusCode = line.slice(0, 2);
    const rawPathText = line.slice(3);
    if (rawPathText.trim() === "") {
        return null;
    }
    const renameSeparator = " -> ";
    const renameIndex = rawPathText.indexOf(renameSeparator);
    const isRenameLike = renameIndex >= 0 && (statusCode.includes("R") || statusCode.includes("C"));
    const originalPath = isRenameLike ? rawPathText.slice(0, renameIndex) : undefined;
    const path = isRenameLike ? rawPathText.slice(renameIndex + renameSeparator.length) : rawPathText;
    return {
        rawLine: line,
        statusCode,
        path,
        originalPath,
        kind: classifyStatusKind(statusCode)
    };
}
function classifyStatusKind(statusCode) {
    if (statusCode === "??") {
        return "untracked";
    }
    if (statusCode.includes("R")) {
        return "renamed";
    }
    if (statusCode.includes("C")) {
        return "copied";
    }
    return "tracked";
}
function unique(values) {
    return [...new Set(values)];
}
function classifyTaskScopedPaths(statusPathEvidence, declaredTargetEvidence) {
    const explicitDeclaredTargets = declaredTargetEvidence
        .filter((entry) => entry.state === "explicit" && entry.path !== undefined)
        .map((entry) => entry.path);
    return unique(statusPathEvidence.map((entry) => entry.path)).map((path) => {
        const scopedToTask = explicitDeclaredTargets.some((declaredPath) => (0, scope_guard_1.isRequestedPathWithinDeclaredTarget)(path, declaredPath));
        return {
            path,
            scopedToTask,
            category: scopedToTask ? classifyScopedPath(path) : "unrelated-to-task"
        };
    });
}
function classifyDocumentationChangedPaths(normalizedChangedPaths, scopedChangedPaths) {
    const scopedChangedPathSet = new Set(scopedChangedPaths);
    return normalizedChangedPaths.map((path) => {
        const classification = (0, documentation_path_classifier_1.classifyDocumentationPath)(path);
        return {
            path,
            category: classification.category,
            documentationOnly: classification.documentationOnly,
            runtimeEligible: classification.runtimeEligible,
            reason: classification.reason,
            scopedToTask: scopedChangedPathSet.has(path)
        };
    });
}
function classifyScopedPath(path) {
    if (path === ".day-shift" || path.startsWith(".day-shift/")) {
        return "planning";
    }
    if (isGeneratedPath(path)) {
        return "generated";
    }
    return "source";
}
function isGeneratedPath(path) {
    return path === "dist"
        || path.startsWith("dist/")
        || path === "coverage"
        || path.startsWith("coverage/")
        || path === "build"
        || path.startsWith("build/")
        || path.endsWith(".tsbuildinfo");
}
