"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getValidationRollupEvidenceSourceInventory = getValidationRollupEvidenceSourceInventory;
exports.getValidationRollupSpecializedBoundaries = getValidationRollupSpecializedBoundaries;
exports.getValidationRollupAggregationContract = getValidationRollupAggregationContract;
exports.isDoctorBlockingFailure = isDoctorBlockingFailure;
exports.deriveDoctorReadinessStatus = deriveDoctorReadinessStatus;
exports.runCoreDoctorChecks = runCoreDoctorChecks;
exports.runScopedDoctorChecks = runScopedDoctorChecks;
exports.createScopedDoctorReport = createScopedDoctorReport;
exports.summarizeDoctorEvidence = summarizeDoctorEvidence;
exports.renderDoctorCheckOutcomeSummary = renderDoctorCheckOutcomeSummary;
exports.renderDoctorFindingSeveritySummary = renderDoctorFindingSeveritySummary;
exports.renderDoctorReportText = renderDoctorReportText;
exports.renderScopedDoctorReportText = renderScopedDoctorReportText;
exports.buildScopedDoctorFullDetailCommand = buildScopedDoctorFullDetailCommand;
exports.renderDoctorErrorDetails = renderDoctorErrorDetails;
exports.renderDoctorCheckSummary = renderDoctorCheckSummary;
exports.renderDoctorGroupedFindings = renderDoctorGroupedFindings;
exports.groupDoctorFindings = groupDoctorFindings;
exports.doctorSeveritySortValue = doctorSeveritySortValue;
exports.renderDoctorFindingPaths = renderDoctorFindingPaths;
// Doctor report contracts, scoped execution, rendering, and validation rollup orchestration.
const node_fs_1 = __importDefault(require("node:fs"));
const output_1 = require("../output");
const runtime_contract_1 = require("../runtime/runtime-contract");
const planning_navigation_1 = require("../planning/planning-navigation");
const planning_document_utils_1 = require("../planning/planning-document-utils");
const validation_links_report_1 = require("../validation/validation-links-report");
const environment_checks_1 = require("./environment-checks");
const hygiene_checks_1 = require("./hygiene-checks");
const planning_checks_1 = require("./planning-checks");
const spec_registry_checks_1 = require("./spec-registry-checks");
const action_relevance_1 = require("./action-relevance");
const check_orchestration_1 = require("./check-orchestration");
const workspace_ignore_1 = require("../workspace-ignore");
const workspace_scan_surface_1 = require("../workspace-scan-surface");
const artifact_lifecycle_1 = require("../planning/artifact-lifecycle");
const paths_1 = require("../paths");
const cli_invocation_1 = require("../runtime/cli-invocation");
const spec_review_1 = require("../spec-review");
const validation_1 = require("../validation");
const contracts_1 = require("./contracts");
const validation_checks_1 = require("./validation-checks");
function getValidationRollupEvidenceSourceInventory() {
    return contracts_1.VALIDATION_ROLLUP_EVIDENCE_SOURCE_INVENTORY.map((source) => ({
        ...source,
        producer: { ...source.producer },
        evidenceShapes: [...source.evidenceShapes],
    }));
}
function getValidationRollupSpecializedBoundaries() {
    return contracts_1.VALIDATION_ROLLUP_SPECIALIZED_BOUNDARIES.map((boundary) => ({
        ...boundary,
        mayReferenceAs: [...boundary.mayReferenceAs],
    }));
}
function getValidationRollupAggregationContract() {
    return {
        ...contracts_1.VALIDATION_ROLLUP_AGGREGATION_CONTRACT,
        lanes: contracts_1.VALIDATION_ROLLUP_AGGREGATION_CONTRACT.lanes.map((lane) => ({
            ...lane,
            authoritativeFor: [...lane.authoritativeFor],
        })),
        sharedFindingFields: [...contracts_1.VALIDATION_ROLLUP_AGGREGATION_CONTRACT.sharedFindingFields],
        sourceLaneFields: [...contracts_1.VALIDATION_ROLLUP_AGGREGATION_CONTRACT.sourceLaneFields],
    };
}
function isDoctorBlockingFailure(report) {
    // Keep blocking behavior anchored to the shared severity model.
    return (0, contracts_1.hasDoctorErrorFinding)(report.findings) || report.summary.errors > 0;
}
function deriveDoctorReadinessStatus(report) {
    if (isDoctorBlockingFailure(report)) {
        return 'blocked';
    }
    if (report.summary.warnings > 0) {
        return 'ready_with_warnings';
    }
    return 'ready';
}
function runCoreDoctorChecks(options = {}) {
    const detection = (0, runtime_contract_1.detectRepositoryRoot)(options.repositoryRoot === undefined ? undefined : { explicitRoot: options.repositoryRoot });
    const repositoryContext = (0, runtime_contract_1.createRepositoryContext)(detection, false);
    let resolvedConfig;
    const orchestration = (0, check_orchestration_1.executeDoctorCheckPlan)([
        {
            id: 'environment',
            run: (findings) => {
                const result = (0, environment_checks_1.runDoctorEnvironmentChecks)({
                    repositoryRoot: repositoryContext.root,
                    detectionSource: detection.detectionSource,
                    findings,
                });
                resolvedConfig = result.resolvedConfig;
                return result.checks;
            },
        },
        { id: 'ignore', run: (findings) => (0, hygiene_checks_1.runIgnoreRecommendationCheck)(repositoryContext.root, findings) },
        { id: 'markdownlint', run: (findings) => (0, hygiene_checks_1.runMarkdownlintRecommendationCheck)(repositoryContext.root, findings) },
    ]);
    const { checks, findings } = orchestration;
    const sandboxParentResult = (0, hygiene_checks_1.runSandboxParentPathIdentityCheck)(repositoryContext.root, findings);
    checks.push(sandboxParentResult.check);
    const sandboxParentPath = sandboxParentResult.sandboxParentPath;
    checks.push((0, hygiene_checks_1.runSandboxPathHygieneCheck)(sandboxParentPath, findings));
    checks.push((0, hygiene_checks_1.runSandboxCleanupReadinessCheck)(repositoryContext.root, sandboxParentPath, findings));
    checks.push((0, planning_checks_1.runPlanningArtifactMetadataCheck)(resolvedConfig, findings));
    checks.push((0, planning_checks_1.runPlanningCliProvenanceCheck)(resolvedConfig, findings));
    checks.push((0, planning_checks_1.runLightweightArtifactStrictnessCheck)(resolvedConfig, findings));
    checks.push((0, spec_registry_checks_1.runSpecRegistryDuplicateIdCheck)(repositoryContext.root, findings));
    checks.push((0, spec_registry_checks_1.runSpecRegistryStructureAndMetadataCheck)(repositoryContext.root, findings));
    checks.push((0, spec_registry_checks_1.runSpecRegistryDestinationSourceAndTraceabilityCheck)(repositoryContext.root, findings));
    const summary = summarizeDoctorEvidence(checks, findings);
    return {
        repositoryRoot: repositoryContext.root,
        detectionSource: repositoryContext.detectionSource,
        checks,
        findings,
        summary,
    };
}
function runScopedDoctorChecks(selection) {
    if (selection.domain === 'repository-audit') {
        const report = runCoreDoctorChecks({ repositoryRoot: selection.repositoryRoot });
        const actionRelevance = selection.actionId === undefined
            ? null
            : (0, action_relevance_1.classifyFindingsForAction)({
                actionId: selection.actionId,
                findings: report.findings,
                context: { healthDomain: selection.domain },
                fullDetailCommand: buildScopedDoctorFullDetailCommand(selection),
            });
        return {
            ...report,
            runtimeProvenance: (0, runtime_contract_1.getRuntimeProvenance)(),
            domain: selection.domain,
            scope: { kind: 'repository', path: '.' },
            readOnly: true,
            producerFamilies: {
                executed: ['runtime-setup', 'workspace-hygiene', 'planning-validation', 'spec-registry'],
                excluded: [],
            },
            completeness: { complete: true, recoveryCommand: null },
            actionRelevance,
        };
    }
    const detection = (0, runtime_contract_1.detectRepositoryRoot)(selection.repositoryRoot === undefined ? undefined : { explicitRoot: selection.repositoryRoot });
    const repositoryContext = (0, runtime_contract_1.createRepositoryContext)(detection, false);
    const checks = [];
    const findings = [];
    if (selection.domain === 'scan-surface') {
        const scanSurface = (0, workspace_scan_surface_1.scanWorkspaceSurfaces)({
            workspaceRoot: repositoryContext.root,
            scanPath: selection.scanPath,
            policy: (0, workspace_ignore_1.createIgnorePolicy)({ workspaceRoot: repositoryContext.root }),
            budgets: selection.repositoryAudit
                ? { files: 50_000, directories: 10_000, metadataBytes: 64_000_000, elapsedMs: 15_000, evidenceEntries: 5_000 }
                : undefined,
        });
        findings.push(...scanSurface.findings.map((finding) => ({
            code: finding.id,
            message: finding.message,
            severity: finding.severity === 'info' ? 'informational' : 'warning',
            ...(finding.path === undefined ? {} : { path: finding.path }),
            evidence: (0, output_1.createValidationCommandEvidence)({
                category: 'validation-rollup',
                details: { source: 'scan-surface', policyId: scanSurface.policy.id, complete: scanSurface.complete },
            }),
        })));
        checks.push({
            id: 'scan-surface',
            status: scanSurface.complete ? (0, validation_checks_1.statusFromFindings)(findings) : 'warning',
            message: scanSurface.complete
                ? `Bounded scan observed ${scanSurface.observed.files} files and ${scanSurface.observed.directories} directories.`
                : `Bounded scan stopped before exceeding the ${scanSurface.exhaustedBudget} budget.`,
        });
        const report = createScopedDoctorReport({
            repositoryRoot: repositoryContext.root,
            detectionSource: repositoryContext.detectionSource,
            domain: selection.domain,
            scope: { kind: 'scan-surface', path: selection.scanPath ?? '.' },
            checks,
            findings,
            executed: ['scan-surface'],
            excluded: ['runtime-setup', 'workspace-hygiene', 'planning-validation', 'spec-registry'],
            actionId: selection.actionId,
        });
        return {
            ...report,
            completeness: {
                complete: scanSurface.complete,
                recoveryCommand: scanSurface.complete
                    ? null
                    : (scanSurface.recovery?.command ?? 'day-shift doctor --scan-surface --repository-audit --format json'),
            },
            scanSurface,
        };
    }
    if (selection.domain === 'runtime') {
        checks.push(...(0, environment_checks_1.runDoctorEnvironmentChecks)({
            repositoryRoot: repositoryContext.root,
            detectionSource: detection.detectionSource,
            findings,
        }).checks);
        return createScopedDoctorReport({
            repositoryRoot: repositoryContext.root,
            detectionSource: repositoryContext.detectionSource,
            domain: selection.domain,
            scope: { kind: 'runtime', path: null },
            checks,
            findings,
            executed: ['runtime-setup'],
            excluded: ['workspace-hygiene', 'planning-validation', 'spec-registry'],
            actionId: selection.actionId,
        });
    }
    const selectedPath = (0, planning_document_utils_1.toRepositoryLikePath)(selection.path).replace(/^\.\//, '');
    if (selection.domain === 'artifact') {
        const artifactText = node_fs_1.default.readFileSync((0, paths_1.resolveRepositoryRelativePath)(repositoryContext.root, (0, paths_1.parseRepositoryRelativePath)(selectedPath)), 'utf8');
        const artifactFamily = (0, validation_1.detectArtifactFamily)({ path: selectedPath, content: artifactText }).family;
        if (artifactFamily === 'specification') {
            try {
                const review = (0, spec_review_1.reviewSpecificationSync)(repositoryContext.root, {
                    specPath: selectedPath,
                    reviewedAt: new Date(0).toISOString(),
                    reviewedBy: 'day-shift-doctor',
                });
                findings.push(...review.findings);
                checks.push({
                    id: 'specification-review',
                    status: (0, validation_checks_1.statusFromFindings)(review.findings),
                    message: review.unresolved_findings.length === 0
                        ? 'Selected specification passed canonical read-only review.'
                        : `Selected specification has ${review.unresolved_findings.length} unresolved review finding${review.unresolved_findings.length === 1 ? '' : 's'}.`,
                });
            }
            catch (error) {
                const message = error instanceof Error ? error.message : String(error);
                findings.push({
                    code: error instanceof spec_review_1.SpecificationReviewError
                        ? `SPEC_REVIEW_${error.code.replace(/-/g, '_').toUpperCase()}`
                        : 'SPEC_REVIEW_FAILED',
                    message,
                    severity: 'error',
                    path: selectedPath,
                    noWriteBoundary: 'Scoped specification doctor failures are no-write outcomes.',
                });
                checks.push({
                    id: 'specification-review',
                    status: 'error',
                    message: 'Selected specification could not complete canonical read-only review.',
                });
            }
            return createScopedDoctorReport({
                repositoryRoot: repositoryContext.root,
                detectionSource: repositoryContext.detectionSource,
                domain: selection.domain,
                scope: { kind: 'artifact', path: selectedPath },
                checks,
                findings,
                executed: ['spec-registry'],
                excluded: ['runtime-setup', 'workspace-hygiene', 'planning-validation'],
                actionId: selection.actionId,
            });
        }
        const lifecycleFindings = (0, artifact_lifecycle_1.createArtifactLifecycleFindings)(selectedPath, (0, artifact_lifecycle_1.readArtifactLifecycleState)(artifactText));
        const linksCheck = (0, validation_links_report_1.runValidationLinksCheckReport)({
            repositoryRoot: repositoryContext.root,
            artifactPath: selectedPath,
        });
        findings.push(...lifecycleFindings, ...linksCheck.findings);
        checks.push({
            id: 'validation-links-check',
            status: (0, validation_checks_1.statusFromFindings)(linksCheck.findings),
            message: linksCheck.findings.length === 0
                ? 'Selected-artifact links-check did not find trace-link lifecycle findings.'
                : `Found ${linksCheck.findings.length} selected-artifact trace-link lifecycle finding${linksCheck.findings.length === 1 ? '' : 's'}.`,
        });
        return createScopedDoctorReport({
            repositoryRoot: repositoryContext.root,
            detectionSource: repositoryContext.detectionSource,
            domain: selection.domain,
            scope: { kind: 'artifact', path: selectedPath },
            checks,
            findings,
            executed: ['planning-validation'],
            excluded: ['runtime-setup', 'workspace-hygiene', 'spec-registry'],
            actionId: selection.actionId,
        });
    }
    const inventory = (0, planning_navigation_1.inventoryPlanning)({
        repositoryRoot: repositoryContext.root,
        rootPath: selectedPath,
    });
    const gaps = (0, planning_navigation_1.gapReportPlanning)({
        repositoryRoot: repositoryContext.root,
        scopePath: selectedPath,
    }).gaps;
    checks.push({
        id: 'planning-inventory',
        status: inventory.findings.length === 0 ? 'ok' : 'warning',
        message: inventory.findings.length === 0
            ? 'Selected planning directory inventory did not find stale paired-artifact state.'
            : `Found ${inventory.findings.length} planning inventory finding${inventory.findings.length === 1 ? '' : 's'} in the selected directory.`,
    }, {
        id: 'planning-gap-report',
        status: (0, validation_checks_1.statusFromPlanningGaps)(gaps),
        message: gaps.length === 0
            ? 'Selected planning directory gap report did not find incomplete downstream artifacts.'
            : `Found ${gaps.length} expected-versus-observed planning gap${gaps.length === 1 ? '' : 's'} in the selected directory.`,
    });
    findings.push(...inventory.findings.map((message) => ({
        code: 'PLANNING_INVENTORY_FINDING',
        message,
        severity: 'warning',
        evidence: (0, output_1.createValidationCommandEvidence)({
            category: 'validation-rollup',
            details: { source: 'planning-inventory' },
        }),
    })), ...gaps.map(validation_checks_1.validationFindingFromPlanningGap));
    return createScopedDoctorReport({
        repositoryRoot: repositoryContext.root,
        detectionSource: repositoryContext.detectionSource,
        domain: selection.domain,
        scope: { kind: 'directory', path: selectedPath },
        checks,
        findings,
        executed: ['planning-validation'],
        excluded: ['runtime-setup', 'workspace-hygiene', 'spec-registry'],
        actionId: selection.actionId,
    });
}
function createScopedDoctorReport(options) {
    const checks = [...options.checks];
    const findings = [...options.findings];
    const actionRelevance = options.actionId === undefined
        ? null
        : (0, action_relevance_1.classifyFindingsForAction)({
            actionId: options.actionId,
            findings,
            context: {
                selectedArtifactPath: options.scope.kind === 'artifact' ? options.scope.path : null,
                healthDomain: options.domain,
            },
            fullDetailCommand: buildScopedDoctorFullDetailCommand({
                domain: options.domain,
                ...(options.scope.path === null || options.domain === 'repository-audit'
                    ? {}
                    : { path: options.scope.path }),
                actionId: options.actionId,
            }),
        });
    return {
        repositoryRoot: options.repositoryRoot,
        detectionSource: options.detectionSource,
        runtimeProvenance: (0, runtime_contract_1.getRuntimeProvenance)(),
        domain: options.domain,
        scope: options.scope,
        readOnly: true,
        producerFamilies: { executed: [...options.executed], excluded: [...options.excluded] },
        completeness: {
            complete: true,
            recoveryCommand: options.domain === 'repository-audit' ? null : 'day-shift doctor --repository-audit --format json',
        },
        actionRelevance,
        checks,
        findings,
        summary: summarizeDoctorEvidence(checks, findings),
    };
}
function summarizeDoctorEvidence(checks, findings) {
    const checkOutcomes = {
        total: checks.length,
        passed: checks.filter((check) => check.status === 'ok').length,
        informational: checks.filter((check) => check.status === 'informational').length,
        warnings: checks.filter((check) => check.status === 'warning').length,
        errors: checks.filter((check) => check.status === 'error').length,
        needingAttention: checks.filter((check) => check.status !== 'ok').length,
    };
    const findingSeverities = {
        total: findings.length,
        informational: findings.filter((finding) => finding.severity === 'informational').length,
        warnings: findings.filter((finding) => finding.severity === 'warning').length,
        errors: findings.filter((finding) => finding.severity === 'error').length,
    };
    return {
        totalChecks: checkOutcomes.total,
        passed: checkOutcomes.passed,
        informational: findingSeverities.informational,
        warnings: findingSeverities.warnings,
        errors: findingSeverities.errors,
        checkOutcomes,
        findingSeverities,
    };
}
function renderDoctorCheckOutcomeSummary(summary) {
    const outcomes = summary.checkOutcomes;
    return `${outcomes.total} total, ${outcomes.passed} passed, ${outcomes.informational} informational, ${outcomes.warnings} warnings, ${outcomes.errors} errors`;
}
function renderDoctorFindingSeveritySummary(summary) {
    const severities = summary.findingSeverities;
    return `${severities.total} total, ${severities.informational} informational, ${severities.warnings} warnings, ${severities.errors} errors`;
}
function renderDoctorReportText(report) {
    const lines = [
        (0, output_1.renderTerminalHeading)('Day Shift workspace doctor', 'title').trimEnd(),
        '',
        (0, output_1.renderTerminalSection)({
            heading: 'Summary',
            fields: [
                { label: 'Repository root', value: report.repositoryRoot },
                { label: 'Detection source', value: report.detectionSource },
                {
                    label: 'Check outcomes',
                    value: renderDoctorCheckOutcomeSummary(report.summary),
                },
                {
                    label: 'Finding severities',
                    value: renderDoctorFindingSeveritySummary(report.summary),
                },
            ],
            lines: [(0, output_1.renderTerminalBoundary)({ kind: 'read-only' })],
        }),
    ];
    if (report.findings.length > 0) {
        lines.push('', renderDoctorGroupedFindings(report.findings));
    }
    return lines.join('\n');
}
function renderScopedDoctorReportText(report) {
    const scopeIdentity = report.scope.path === null ? report.scope.kind : `${report.scope.kind}:${report.scope.path}`;
    const lines = [
        (0, output_1.renderTerminalHeading)('Day Shift workspace doctor', 'title').trimEnd(),
        '',
        (0, output_1.renderTerminalSection)({
            heading: 'Summary',
            fields: [
                { label: 'Repository root', value: report.repositoryRoot },
                { label: 'Detection source', value: report.detectionSource },
                { label: 'Health domain', value: report.domain },
                { label: 'Selected scope', value: scopeIdentity },
                { label: 'Complete', value: report.completeness.complete ? 'yes' : 'no' },
                { label: 'Selected action', value: report.actionRelevance?.selectedAction.command ?? 'none' },
                { label: 'Current-action blockers', value: report.actionRelevance?.currentActionBlockers.length ?? 0 },
                {
                    label: 'Check outcomes',
                    value: renderDoctorCheckOutcomeSummary(report.summary),
                },
                {
                    label: 'Finding severities',
                    value: renderDoctorFindingSeveritySummary(report.summary),
                },
            ],
            lines: [(0, output_1.renderTerminalBoundary)({ kind: 'read-only' })],
        }),
    ];
    if (report.completeness.recoveryCommand !== null) {
        lines.push('', `Broader audit: ${report.completeness.recoveryCommand}`);
    }
    if (report.actionRelevance !== null) {
        lines.push('', `Full action detail: ${report.actionRelevance.fullDetailCommand}`);
        lines.push('', (0, output_1.renderTerminalCompactList)({
            heading: 'Current-action blockers by code:',
            entries: report.actionRelevance.blockerGroups.map((group) => ({
                label: group.code,
                fields: [
                    { label: 'Count', value: group.count },
                    { label: 'Rule', value: group.representative.ruleId },
                    { label: 'Message', value: group.representative.originalFinding.message },
                ],
            })),
            emptyMessage: 'No blockers apply to the selected action.',
        }));
    }
    if (report.findings.length > 0) {
        lines.push('', renderDoctorGroupedFindings(report.findings));
    }
    return lines.join('\n');
}
function buildScopedDoctorFullDetailCommand(selection) {
    const args = ['doctor'];
    if (selection.domain === 'runtime')
        args.push('--runtime-only');
    if (selection.domain === 'artifact')
        args.push('--artifact', selection.path);
    if (selection.domain === 'planning')
        args.push('--planning-directory', selection.path);
    if (selection.domain === 'scan-surface') {
        args.push('--scan-surface');
        if (selection.scanPath !== undefined)
            args.push('--scan-path', JSON.stringify(selection.scanPath));
        if (selection.repositoryAudit)
            args.push('--repository-audit');
    }
    if (selection.domain === 'repository-audit')
        args.push('--repository-audit');
    if (selection.actionId !== undefined)
        args.push('--action', JSON.stringify(selection.actionId));
    args.push('--format', 'json', '--detail', 'full');
    return (0, cli_invocation_1.renderDayShiftCliCommand)(args.join(' '));
}
function renderDoctorErrorDetails(report) {
    return [
        '',
        (0, output_1.renderTerminalSection)({
            heading: 'Summary',
            fields: [
                { label: 'Repository root', value: report.repositoryRoot },
                { label: 'Detection source', value: report.detectionSource },
                {
                    label: 'Check outcomes',
                    value: renderDoctorCheckOutcomeSummary(report.summary),
                },
                {
                    label: 'Finding severities',
                    value: renderDoctorFindingSeveritySummary(report.summary),
                },
            ],
            lines: [(0, output_1.renderTerminalBoundary)({ kind: 'read-only' })],
        }),
        '',
        renderDoctorCheckSummary(report.checks, report.findings),
        '',
        renderDoctorGroupedFindings(report.findings),
    ];
}
function renderDoctorCheckSummary(checks, findings) {
    const relevantChecks = checks.filter((check) => check.status !== 'ok');
    return (0, output_1.renderTerminalCompactList)({
        heading: 'Checks needing attention',
        entries: relevantChecks.map((check) => ({
            label: `${check.id} (${check.status})`,
            fields: [{ label: 'Message', value: check.message }],
        })),
        emptyMessage: findings.length > 0
            ? 'No check outcomes need attention; finding severities are reported separately below.'
            : 'No checks need attention.',
    });
}
function renderDoctorGroupedFindings(findings) {
    const groups = groupDoctorFindings(findings);
    return (0, output_1.renderTerminalCompactList)({
        heading: 'Findings by issue',
        entrySpacing: 'loose',
        entries: groups.map((group) => ({
            label: `[${group.severity}] ${group.code}`,
            fields: [
                { label: 'Count', value: group.findings.length },
                { label: 'Message', value: group.message },
            ],
            lines: renderDoctorFindingPaths(group.findings),
        })),
        emptyMessage: 'No findings.',
    });
}
function groupDoctorFindings(findings) {
    const groups = new Map();
    for (const finding of findings) {
        const key = [finding.severity, finding.code, finding.message].join('\u0000');
        const existingGroup = groups.get(key);
        if (existingGroup !== undefined) {
            existingGroup.findings.push(finding);
            continue;
        }
        groups.set(key, {
            severity: finding.severity,
            code: finding.code,
            message: finding.message,
            findings: [finding],
        });
    }
    return Array.from(groups.values()).sort((left, right) => doctorSeveritySortValue(left.severity) - doctorSeveritySortValue(right.severity) ||
        left.code.localeCompare(right.code) ||
        left.message.localeCompare(right.message));
}
function doctorSeveritySortValue(severity) {
    if (severity === 'error') {
        return 0;
    }
    if (severity === 'warning') {
        return 1;
    }
    return 2;
}
function renderDoctorFindingPaths(findings) {
    const findingsByPath = new Map();
    for (const finding of findings) {
        const findingPath = finding.path;
        if (findingPath === undefined || findingPath.trim() === '' || findingsByPath.has(findingPath)) {
            continue;
        }
        findingsByPath.set(findingPath, finding);
    }
    const pathEntries = Array.from(findingsByPath.entries());
    if (pathEntries.length === 0) {
        return [];
    }
    const visiblePathEntries = pathEntries.slice(0, contracts_1.DOCTOR_TEXT_PATH_PREVIEW_LIMIT);
    const hiddenPathCount = pathEntries.length - visiblePathEntries.length;
    return [
        hiddenPathCount > 0 ? 'Paths (first 12):' : 'Paths:',
        ...visiblePathEntries.flatMap(([findingPath, finding]) => [
            `- ${findingPath}`,
            ...renderDoctorFindingRecovery(finding.recovery),
        ]),
        ...(hiddenPathCount > 0
            ? [`Additional paths: ${hiddenPathCount} more; rerun with --format json for the full finding payload.`]
            : []),
    ];
}
function renderDoctorFindingRecovery(recovery) {
    if (recovery === undefined) {
        return [];
    }
    if (typeof recovery === 'string') {
        return [`  Recovery: ${recovery}`];
    }
    return [
        '  Recovery options:',
        ...recovery.map((step) => `  - ${step}`),
    ];
}
