"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createVersionDoctorReport = createVersionDoctorReport;
exports.renderVersionDoctorReport = renderVersionDoctorReport;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const output_1 = require("../output");
const license_resolution_1 = require("../license/license-resolution");
const runtime_contract_1 = require("../runtime/runtime-contract");
const runtime_state_1 = require("./runtime-state");
const selection_1 = require("./selection");
function createVersionDoctorReport(env = process.env) {
    const versionManagerRoot = (0, runtime_state_1.resolveVersionManagerRoot)(env);
    const statePaths = createStatePaths(versionManagerRoot);
    const selectedMetadataPath = node_path_1.default.join(versionManagerRoot, "selected-version.json");
    const selection = (0, selection_1.resolveManagedVersionSelection)({ env, cwd: process.cwd() });
    const resolution = (0, runtime_state_1.resolveSelectedManagedCli)({ env, currentExecutablePath: process.argv[1] });
    const pathCandidates = findDayShiftPathCandidates(env.PATH);
    const configuredShimPath = env[runtime_state_1.DAY_SHIFT_SHIM_PATH_ENV]?.trim() || null;
    const normalizedExpected = configuredShimPath === null
        ? null
        : normalizeExistingPath(configuredShimPath);
    const firstExistingCandidate = pathCandidates.find((candidate) => candidate.exists);
    const pathConflict = normalizedExpected !== null &&
        firstExistingCandidate !== undefined &&
        normalizeExistingPath(firstExistingCandidate.path) !== normalizedExpected;
    const diagnostics = [
        ...createPathDiagnostics({ pathConflict, firstExistingCandidate, configuredShimPath }),
        ...createShimDiagnostics({ configuredShimPath, pathCandidates }),
        ...createSelectionDiagnostics(selection),
        ...createInstalledMetadataDiagnostics(versionManagerRoot)
    ];
    const selectedLicense = selection.ok
        ? summarizeLicenseStatus((0, license_resolution_1.resolveLicenseStatus)({
            repositoryContext: (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false),
            env,
            currentCliVersion: selection.version
        }))
        : null;
    if (selectedLicense?.current_version_coverage_state === "not-covered") {
        diagnostics.push({
            code: "license-not-covered",
            severity: "warning",
            message: `Selected version ${selection.ok ? selection.version : "(none)"} is not covered by the configured license.`,
            path: selectedLicense.license_path,
            selector: selection.ok ? selection.selector : null
        });
    }
    if (resolution.ok && selection.ok) {
        return {
            version_manager_root: versionManagerRoot,
            state_paths: statePaths,
            selected_metadata_path: selectedMetadataPath,
            selected_version: selection.version,
            selection,
            package_root: selection.packageDirectory,
            executable_path: resolution.target.executablePath,
            selected_license: selectedLicense,
            runtime_status: "ready",
            failure_reason: null,
            failure_message: null,
            failure_details: [],
            shim_mode: (0, runtime_state_1.isVersionManagerShimMode)(env),
            manager_entrypoint: process.argv[1],
            configured_shim_path: configuredShimPath,
            path_candidates: pathCandidates,
            path_conflict: pathConflict,
            diagnostics,
            read_only: true,
            network_attempted: false
        };
    }
    let failureReason;
    let failureMessage;
    let failureDetails;
    if (!selection.ok) {
        failureReason = selection.reason;
        failureMessage = selection.message;
        failureDetails = selection.details;
    }
    else if (!resolution.ok) {
        failureReason = resolution.reason;
        failureMessage = resolution.message;
        failureDetails = resolution.details;
    }
    else {
        failureReason = "unknown-runtime-state";
        failureMessage = "Version doctor could not classify the runtime state.";
        failureDetails = [];
    }
    return {
        version_manager_root: versionManagerRoot,
        state_paths: statePaths,
        selected_metadata_path: selectedMetadataPath,
        selected_version: null,
        selection,
        package_root: null,
        executable_path: null,
        selected_license: selectedLicense,
        runtime_status: "not-ready",
        failure_reason: failureReason,
        failure_message: failureMessage,
        failure_details: failureDetails,
        shim_mode: (0, runtime_state_1.isVersionManagerShimMode)(env),
        manager_entrypoint: process.argv[1],
        configured_shim_path: configuredShimPath,
        path_candidates: pathCandidates,
        path_conflict: pathConflict,
        diagnostics: [
            ...diagnostics,
            {
                code: failureReason,
                severity: "error",
                message: failureMessage,
                path: selectedMetadataPath,
                selector: selection.ok ? selection.selector : selection.selector
            }
        ],
        read_only: true,
        network_attempted: false
    };
}
function renderVersionDoctorReport(report, _format) {
    return [
        (0, output_1.renderTerminalSection)({
            heading: "Day Shift version doctor",
            headingStyle: "title",
            fields: [
                { label: "Runtime status", value: report.runtime_status },
                { label: "Version manager root", value: report.version_manager_root },
                { label: "Versions directory", value: report.state_paths.versions_directory },
                { label: "Aliases directory", value: report.state_paths.aliases_directory },
                { label: "Receipts directory", value: report.state_paths.receipts_directory },
                { label: "Shims directory", value: report.state_paths.shims_directory },
                { label: "Selected metadata path", value: report.selected_metadata_path },
                { label: "Selected version", value: report.selected_version },
                { label: "Package root", value: report.package_root },
                { label: "Executable path", value: report.executable_path },
                { label: "Shim mode", value: report.shim_mode },
                { label: "Manager entrypoint", value: report.manager_entrypoint },
                { label: "Configured shim path", value: report.configured_shim_path },
                { label: "PATH conflict", value: report.path_conflict },
                { label: "Read only", value: report.read_only },
                { label: "Network attempted", value: report.network_attempted }
            ]
        }),
        (0, output_1.renderTerminalSection)({
            heading: "Selected license",
            headingStyle: "section",
            fields: [
                { label: "Status", value: report.selected_license?.effective_status ?? "(none)" },
                { label: "Reason", value: report.selected_license?.reason_code ?? "(none)" },
                { label: "Covered release line", value: report.selected_license?.covered_release_line ?? "(none)" },
                { label: "Coverage state", value: report.selected_license?.current_version_coverage_state ?? "(none)" },
                { label: "Coverage path", value: report.selected_license?.effective_coverage_path ?? "(none)" },
                { label: "License path", value: report.selected_license?.license_path ?? "(none)" }
            ]
        }),
        (0, output_1.renderTerminalSection)({
            heading: "Failure",
            headingStyle: "section",
            fields: [
                { label: "Reason", value: report.failure_reason },
                { label: "Message", value: report.failure_message }
            ],
            lines: report.failure_details
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: "PATH candidates",
            headingStyle: "section",
            entries: report.path_candidates.map((candidate) => ({
                label: candidate.path,
                fields: [{ label: "Exists", value: candidate.exists }]
            })),
            emptyMessage: "No day-shift candidates found on PATH."
        }),
        (0, output_1.renderTerminalCompactList)({
            heading: "Diagnostics",
            headingStyle: "section",
            entries: report.diagnostics.map((diagnostic) => ({
                label: diagnostic.code,
                fields: [
                    { label: "Severity", value: diagnostic.severity },
                    { label: "Path", value: diagnostic.path ?? "(none)" },
                    { label: "Selector", value: diagnostic.selector ?? "(none)" }
                ],
                lines: [diagnostic.message]
            })),
            emptyMessage: "(none)"
        })
    ].join("\n\n");
}
function createStatePaths(versionManagerRoot) {
    return {
        versions_directory: node_path_1.default.join(versionManagerRoot, "versions"),
        aliases_directory: node_path_1.default.join(versionManagerRoot, "aliases"),
        receipts_directory: node_path_1.default.join(versionManagerRoot, "installs", "receipts"),
        shims_directory: node_path_1.default.join(versionManagerRoot, "shims")
    };
}
function createPathDiagnostics(options) {
    if (!options.pathConflict) {
        return [];
    }
    return [{
            code: "path-conflict",
            severity: "warning",
            message: "The first day-shift executable on PATH does not match the configured shim path.",
            path: options.firstExistingCandidate?.path ?? null,
            selector: options.configuredShimPath
        }];
}
function createShimDiagnostics(options) {
    const diagnostics = [];
    if (options.configuredShimPath === null) {
        diagnostics.push({
            code: "shim-path-not-configured",
            severity: "warning",
            message: `${runtime_state_1.DAY_SHIFT_SHIM_PATH_ENV} is not configured, so doctor cannot verify the intended stable shim path.`,
            path: null,
            selector: null
        });
    }
    else if (!node_fs_1.default.existsSync(options.configuredShimPath)) {
        diagnostics.push({
            code: "missing-shim",
            severity: "error",
            message: "The configured stable shim path does not exist.",
            path: options.configuredShimPath,
            selector: null
        });
    }
    if (options.pathCandidates.length === 0) {
        diagnostics.push({
            code: "day-shift-not-on-path",
            severity: "warning",
            message: "No day-shift executable was found on PATH.",
            path: null,
            selector: null
        });
    }
    return diagnostics;
}
function createSelectionDiagnostics(selection) {
    if (selection.ok) {
        return [{
                code: "selected-version-ready",
                severity: "info",
                message: `Selected version ${selection.version} from ${selection.source}.`,
                path: selection.metadataPath,
                selector: selection.selector
            }];
    }
    return [{
            code: selection.reason,
            severity: "error",
            message: selection.message,
            path: null,
            selector: selection.selector
        }];
}
function createInstalledMetadataDiagnostics(versionManagerRoot) {
    const versionsDirectory = node_path_1.default.join(versionManagerRoot, "versions");
    if (!node_fs_1.default.existsSync(versionsDirectory)) {
        return [];
    }
    return node_fs_1.default.readdirSync(versionsDirectory, { withFileTypes: true })
        .filter((entry) => entry.isDirectory())
        .flatMap((entry) => inspectInstalledVersionDirectory(node_path_1.default.join(versionsDirectory, entry.name), entry.name));
}
function inspectInstalledVersionDirectory(versionDirectory, directoryName) {
    const diagnostics = [];
    const metadataPath = node_path_1.default.join(versionDirectory, "metadata.json");
    const packageRoot = node_path_1.default.join(versionDirectory, "package");
    if (!node_fs_1.default.existsSync(metadataPath)) {
        diagnostics.push({
            code: "missing-installed-metadata",
            severity: "error",
            message: `Installed version directory ${directoryName} is missing metadata.json.`,
            path: metadataPath,
            selector: directoryName
        });
    }
    else {
        try {
            const parsed = JSON.parse(node_fs_1.default.readFileSync(metadataPath, "utf8"));
            if (typeof parsed !== "object" || parsed === null || parsed.version !== directoryName) {
                diagnostics.push({
                    code: "malformed-installed-metadata",
                    severity: "error",
                    message: "Installed version metadata must include a version matching its directory name.",
                    path: metadataPath,
                    selector: directoryName
                });
            }
        }
        catch (error) {
            diagnostics.push({
                code: "malformed-installed-metadata",
                severity: "error",
                message: error instanceof Error ? error.message : String(error),
                path: metadataPath,
                selector: directoryName
            });
        }
    }
    if (!node_fs_1.default.existsSync(packageRoot) || !node_fs_1.default.statSync(packageRoot).isDirectory()) {
        diagnostics.push({
            code: "missing-package-root",
            severity: "error",
            message: `Installed version directory ${directoryName} is missing its package root.`,
            path: packageRoot,
            selector: directoryName
        });
    }
    return diagnostics;
}
function summarizeLicenseStatus(status) {
    return {
        effective_status: status.effective_status,
        reason_code: status.reason_code,
        covered_release_line: status.covered_release_line,
        current_version_coverage_state: status.current_version_coverage_state,
        effective_coverage_path: status.effective_coverage_path,
        license_path: status.license_path
    };
}
function findDayShiftPathCandidates(pathValue) {
    const entries = (pathValue ?? "")
        .split(node_path_1.default.delimiter)
        .filter((entry) => entry.trim() !== "");
    const executableNames = process.platform === "win32"
        ? ["day-shift.cmd", "day-shift.exe", "day-shift"]
        : ["day-shift"];
    const candidates = [];
    for (const entry of entries) {
        for (const executableName of executableNames) {
            const candidatePath = node_path_1.default.join(entry, executableName);
            const exists = node_fs_1.default.existsSync(candidatePath);
            if (exists) {
                candidates.push({ path: candidatePath, exists });
            }
        }
    }
    return candidates;
}
function normalizeExistingPath(inputPath) {
    const resolved = node_path_1.default.resolve(inputPath);
    try {
        return node_fs_1.default.realpathSync(resolved);
    }
    catch {
        return resolved;
    }
}
