/**
 * DiagnosticRunner
 *
 * Implementation of `IDiagnosticRunner` for `shep doctor`. Runs every
 * diagnostic in parallel via `Promise.allSettled` with a per-diagnostic
 * timeout (default 3 s, NFR-7). Worst-case wall-clock = the slowest single
 * check, not the sum.
 *
 * Failures and timeouts surface as structured `DiagnosticResult`s rather
 * than rejected promises so the report always populates fully.
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { injectable } from 'tsyringe';
import { DiagnosticStatus } from '../../../domain/generated/output.js';
const DEFAULT_TIMEOUT_MS = 3000;
function rankOf(status) {
    switch (status) {
        case DiagnosticStatus.Fail:
            return 2;
        case DiagnosticStatus.Warn:
            return 1;
        case DiagnosticStatus.Ok:
        default:
            return 0;
    }
}
function worst(a, b) {
    return rankOf(a) >= rankOf(b) ? a : b;
}
function timeoutResult(name, timeoutMs, durationMs) {
    return {
        name,
        status: DiagnosticStatus.Warn,
        detail: `Diagnostic "${name}" exceeded ${timeoutMs}ms timeout — marked warn so it does not block doctor`,
        durationMs,
    };
}
function errorResult(name, err, durationMs) {
    const message = err instanceof Error ? err.message : String(err);
    return {
        name,
        status: DiagnosticStatus.Fail,
        detail: `Diagnostic "${name}" threw: ${message}`,
        durationMs,
    };
}
let DiagnosticRunner = class DiagnosticRunner {
    timeoutMs;
    constructor(options = {}) {
        this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
    }
    async runAll(diagnostics) {
        const overallStart = Date.now();
        if (diagnostics.length === 0) {
            return { results: [], overallStatus: DiagnosticStatus.Ok, totalDurationMs: 0 };
        }
        const settled = await Promise.allSettled(diagnostics.map((d) => this.runOne(d)));
        const results = settled.map((r, i) => {
            if (r.status === 'fulfilled')
                return r.value;
            return errorResult(diagnostics[i].name, r.reason, 0);
        });
        const overallStatus = results.reduce((acc, r) => worst(acc, r.status), DiagnosticStatus.Ok);
        return {
            results,
            overallStatus,
            totalDurationMs: Date.now() - overallStart,
        };
    }
    async runOne(d) {
        const start = Date.now();
        let timer;
        const timeout = new Promise((resolve) => {
            timer = setTimeout(() => resolve(timeoutResult(d.name, this.timeoutMs, Date.now() - start)), this.timeoutMs);
        });
        try {
            const result = await Promise.race([d.run(), timeout]);
            if (timer)
                clearTimeout(timer);
            return { ...result, durationMs: result.durationMs ?? Date.now() - start };
        }
        catch (err) {
            if (timer)
                clearTimeout(timer);
            return errorResult(d.name, err, Date.now() - start);
        }
    }
};
DiagnosticRunner = __decorate([
    injectable(),
    __metadata("design:paramtypes", [Object])
], DiagnosticRunner);
export { DiagnosticRunner };
