"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createScanSafetyEvidence = createScanSafetyEvidence;
const node_crypto_1 = require("node:crypto");
const workspace_ignore_1 = require("../workspace-ignore");
const workspace_scan_surface_1 = require("../workspace-scan-surface");
const workspace_traversal_1 = require("../workspace-traversal");
function createScanSafetyEvidence(options) {
    const policy = options.policy ?? (0, workspace_ignore_1.createIgnorePolicy)({ workspaceRoot: options.workspaceRoot });
    const scanPath = normalizeScanPath(options.scanPath);
    const traversal = (0, workspace_traversal_1.traverseWorkspace)({
        workspaceRoot: options.workspaceRoot,
        startPath: scanPath === "." ? undefined : scanPath,
        policy,
        budgets: { ...workspace_traversal_1.DEFAULT_TRAVERSAL_BUDGETS, ...options.budgets },
        readContent: false,
        now: options.now
    });
    const thresholds = { ...workspace_scan_surface_1.DEFAULT_SCAN_SURFACE_THRESHOLDS, ...options.thresholds };
    const eligibleBytesBySurface = new Map();
    let approximateBytes = 0;
    for (const entry of traversal.entries) {
        if (entry.kind !== "file")
            continue;
        approximateBytes += entry.size;
        if ((0, workspace_scan_surface_1.classifyScanSurface)(entry.path) !== "eligible")
            continue;
        const surfacePath = firstPathSegment(entry.path);
        eligibleBytesBySurface.set(surfacePath, (eligibleBytesBySurface.get(surfacePath) ?? 0) + entry.size);
    }
    const findings = [];
    if (approximateBytes >= thresholds.informationalBytes) {
        findings.push({
            id: "SCAN_SURFACE_SIZE_INFORMATION",
            severity: "info",
            message: `Observed eligible files total approximately ${approximateBytes} bytes; repository size alone is informational.`
        });
    }
    for (const [surfacePath, surfaceBytes] of [...eligibleBytesBySurface.entries()]
        .sort(([leftPath, leftBytes], [rightPath, rightBytes]) => (rightBytes - leftBytes || leftPath.localeCompare(rightPath, "en")))
        .slice(0, thresholds.largestSurfaceCount)) {
        if (surfaceBytes < thresholds.actionableEligibleBytes)
            continue;
        findings.push({
            id: "SCAN_SURFACE_INDEXING_RISK",
            severity: "warning",
            path: surfacePath,
            message: `Eligible surface '${surfacePath}' remains large enough to present indexing risk.`
        });
    }
    if (!traversal.complete) {
        findings.push({
            id: "SCAN_SURFACE_INCOMPLETE",
            severity: "warning",
            path: traversal.omission?.nextPath,
            message: `Scan stopped before exceeding the ${traversal.exhaustedBudget} budget; no complete-health claim is available.`
        });
    }
    const actionDecision = !traversal.complete
        ? "diagnostic-required"
        : findings.some((finding) => finding.id === "SCAN_SURFACE_INDEXING_RISK")
            ? "editor-preview-relevant"
            : "sufficient";
    const identityInput = {
        policy: {
            id: policy.id,
            version: policy.version,
            sources: policy.sources.map((source) => ({
                id: source.id,
                kind: source.kind,
                rules: source.rules.map((rule) => ({
                    pattern: rule.pattern,
                    decision: rule.decision,
                    rationale: rule.rationale
                }))
            }))
        },
        scanPath,
        entries: traversal.entries
            .map((entry) => ({ path: entry.path, kind: entry.kind, size: entry.size }))
            .sort((left, right) => left.path.localeCompare(right.path, "en")),
        traversalFindings: traversal.findings
            .map((finding) => ({ code: finding.code, path: finding.path, message: finding.message }))
            .sort((left, right) => left.path.localeCompare(right.path, "en") || left.code.localeCompare(right.code, "en")),
        completeness: {
            complete: traversal.complete,
            exhaustedBudget: traversal.exhaustedBudget ?? null,
            nextPath: traversal.omission?.nextPath ?? null
        }
    };
    return Object.freeze({
        evidenceId: `sha256:${(0, node_crypto_1.createHash)("sha256").update(JSON.stringify(identityInput)).digest("hex")}`,
        policyId: policy.id,
        policyVersion: policy.version,
        scanPath,
        observedAt: options.observedAt ?? new Date().toISOString(),
        observationalFields: Object.freeze(["observedAt"]),
        freshness: "current",
        complete: traversal.complete,
        healthClaim: "not-assessed",
        findings: Object.freeze(findings),
        actionDecision,
        ...(actionDecision === "diagnostic-required" ? {
            diagnosticCommand: "day-shift doctor --scan-surface --format json"
        } : {}),
        ...(actionDecision === "editor-preview-relevant" ? {
            editorPreviewCommand: "day-shift ignore integration preview --target vscode --format json"
        } : {})
    });
}
function normalizeScanPath(scanPath) {
    if (scanPath === undefined || scanPath.trim() === "" || scanPath.trim() === ".")
        return ".";
    return scanPath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
}
function firstPathSegment(input) {
    const normalized = input.replace(/\\/g, "/").replace(/^\.\//, "");
    return normalized.split("/").filter(Boolean)[0] ?? ".";
}
