"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDoctorCommand = createDoctorCommand;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../../lib/errors");
const output_1 = require("../../lib/output");
const doctor_1 = require("../../lib/doctor");
const config_contract_1 = require("../../lib/config/config-contract");
const paths_1 = require("../../lib/paths");
async function createDoctorCommand() {
    const { Command } = await import("commander");
    const command = new Command("doctor");
    command
        .description("Diagnose baseline Day Shift workspace health using read-only checks.")
        .option("--runtime-only", "Run only runtime and workspace-setup health checks.")
        .option("--artifact <path>", "Run health checks for one selected planning artifact.")
        .option("--planning-directory <path>", "Run health checks for one selected planning directory.")
        .option("--scan-surface", "Run the bounded read-only workspace scan-surface diagnostic.")
        .option("--scan-path <path>", "Start a scan-surface diagnostic at one repository-relative subtree.")
        .option("--repository-audit", "Run the authoritative repository-wide audit (the default).")
        .option("--action <command>", "Classify findings for one exact authoritative command descriptor.")
        .action((_, commandInstance) => {
        const format = (0, output_1.resolveOutputFormat)(commandInstance.optsWithGlobals().format);
        if (format === null) {
            throw (0, errors_1.createUsageError)("Output format must be one of: text, json.", [`Received: ${String(commandInstance.optsWithGlobals().format)}`]);
        }
        const repositoryContext = getRootCommand(commandInstance).configRepositoryContext;
        const options = commandInstance.opts();
        const selection = resolveDoctorSelection({
            repositoryContext,
            runtimeOnly: options.runtimeOnly === true,
            artifact: options.artifact,
            planningDirectory: options.planningDirectory,
            scanSurface: options.scanSurface === true,
            scanPath: options.scanPath,
            repositoryAudit: options.repositoryAudit === true,
            action: options.action
        });
        const report = (0, doctor_1.runScopedDoctorChecks)(selection);
        const readinessStatus = (0, doctor_1.deriveDoctorReadinessStatus)(report);
        const blockingFailure = report.actionRelevance === null
            ? readinessStatus === "blocked" || (0, doctor_1.isDoctorBlockingFailure)(report)
            : report.actionRelevance.currentActionBlockers.length > 0;
        if (blockingFailure) {
            throw new errors_1.RuntimeError({
                message: "Doctor found core workspace health errors.",
                code: "DOCTOR_CHECK_FAILED",
                exitCode: errors_1.RuntimeExitCode.ERROR,
                details: [...(0, doctor_1.renderDoctorErrorDetails)(report)],
                findings: report.actionRelevance === null
                    ? [...report.findings]
                    : report.actionRelevance.currentActionBlockers.map(doctor_1.toActionRelevanceValidationFinding)
            });
        }
        (0, output_1.emitSuccess)({
            command: "doctor",
            format,
            text: (0, doctor_1.renderScopedDoctorReportText)(report),
            data: {
                repositoryRoot: report.repositoryRoot,
                detectionSource: report.detectionSource,
                runtimeProvenance: report.runtimeProvenance,
                domain: report.domain,
                scope: report.scope,
                readOnly: report.readOnly,
                producerFamilies: report.producerFamilies,
                completeness: report.completeness,
                scanSurface: report.scanSurface ?? null,
                actionRelevance: report.actionRelevance,
                checks: report.checks,
                summary: report.summary,
                readinessStatus
            },
            findings: [...report.findings]
        });
    });
    return command;
}
function resolveDoctorSelection(options) {
    const selectors = [
        options.runtimeOnly,
        options.artifact !== undefined,
        options.planningDirectory !== undefined,
        options.scanSurface,
        options.repositoryAudit && !options.scanSurface
    ].filter(Boolean).length;
    if (selectors > 1) {
        throw (0, errors_1.createUsageError)("Doctor scope inputs are mutually exclusive.", ["Choose only one of --runtime-only, --artifact, --planning-directory, or --scan-surface; --repository-audit may deepen --scan-surface."]);
    }
    const repositoryRoot = options.repositoryContext?.root ?? process.cwd();
    if (options.scanPath !== undefined && !options.scanSurface) {
        throw (0, errors_1.createUsageError)("Doctor --scan-path requires --scan-surface.");
    }
    const scanPath = options.scanPath === undefined ? undefined : validateScanPath(options.scanPath, repositoryRoot);
    const actionId = resolveActionId(options.action);
    if (options.runtimeOnly)
        return { domain: "runtime", repositoryRoot, actionId };
    if (options.scanSurface)
        return { domain: "scan-surface", repositoryRoot, repositoryAudit: options.repositoryAudit, scanPath, actionId };
    if (options.artifact !== undefined) {
        return {
            domain: "artifact",
            path: validatePlanningTarget(options.artifact, "file", repositoryRoot, options.repositoryContext),
            repositoryRoot,
            actionId
        };
    }
    if (options.planningDirectory !== undefined) {
        return {
            domain: "planning",
            path: validatePlanningTarget(options.planningDirectory, "directory", repositoryRoot, options.repositoryContext),
            repositoryRoot,
            actionId
        };
    }
    return { domain: "repository-audit", repositoryRoot, actionId };
}
function validateScanPath(input, repositoryRoot) {
    const absolutePath = node_path_1.default.resolve(repositoryRoot, input);
    const relativePath = node_path_1.default.relative(repositoryRoot, absolutePath);
    if (relativePath === ".." || relativePath.startsWith(`..${node_path_1.default.sep}`) || node_path_1.default.isAbsolute(relativePath)) {
        throw (0, errors_1.createUsageError)("Doctor scan path must remain inside the repository root.", [`Received: ${input}`]);
    }
    if (!node_fs_1.default.existsSync(absolutePath) || !node_fs_1.default.statSync(absolutePath).isDirectory()) {
        throw (0, errors_1.createUsageError)("Doctor scan path must be an existing directory.", [`Received: ${input}`]);
    }
    return (0, paths_1.toRepositoryRelativePath)(repositoryRoot, absolutePath);
}
function resolveActionId(input) {
    if (input === undefined)
        return undefined;
    const actionId = input.trim();
    const descriptor = (0, output_1.getRegisteredCommandDescriptor)(actionId);
    if (actionId === "" || descriptor === null || descriptor.availability !== "callable") {
        throw (0, errors_1.createUsageError)("Doctor action must match one authoritative callable command descriptor.", [
            `Received: ${input}`,
            "Use day-shift commands search <query> --format json to discover exact command identities."
        ]);
    }
    return actionId;
}
function validatePlanningTarget(input, expectedKind, repositoryRoot, repositoryContext) {
    const resolvedConfig = (0, config_contract_1.resolveDayShiftConfig)({ repositoryContext });
    const planningRoot = node_path_1.default.resolve(resolvedConfig.derived.planningRootPath);
    const absolutePath = node_path_1.default.resolve(repositoryRoot, input);
    const withinPlanningRoot = absolutePath === planningRoot
        || absolutePath.startsWith(`${planningRoot}${node_path_1.default.sep}`);
    if (!withinPlanningRoot) {
        throw (0, errors_1.createUsageError)("Doctor selected scope must stay inside the configured planning root.", [`Received: ${input}`, `Planning root: ${(0, paths_1.toRepositoryRelativePath)(repositoryRoot, planningRoot)}`]);
    }
    if (!node_fs_1.default.existsSync(absolutePath)) {
        throw (0, errors_1.createUsageError)("Doctor selected scope does not exist.", [`Received: ${input}`]);
    }
    const stats = node_fs_1.default.statSync(absolutePath);
    if ((expectedKind === "file" && !stats.isFile())
        || (expectedKind === "directory" && !stats.isDirectory())) {
        throw (0, errors_1.createUsageError)(`Doctor selected scope must be an existing ${expectedKind}.`, [`Received: ${input}`]);
    }
    if (expectedKind === "file" && node_path_1.default.extname(absolutePath).toLowerCase() !== ".md") {
        throw (0, errors_1.createUsageError)("Doctor selected artifact must be a Markdown planning artifact.", [`Received: ${input}`]);
    }
    return (0, paths_1.toRepositoryRelativePath)(repositoryRoot, absolutePath);
}
function getRootCommand(commandInstance) {
    let current = commandInstance;
    while (current?.parent)
        current = current.parent;
    return current ?? commandInstance;
}
