"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.collectAuthDoctorChecks = collectAuthDoctorChecks;
const availability_1 = require("../../auth-profiles/availability");
const kind_1 = require("../../auth-profiles/kind");
const store_1 = require("../../auth-profiles/store");
const control_plane_config_1 = require("../../config/control-plane-config");
const command_1 = require("../../core/command");
const catalog_1 = require("../../i18n/catalog");
const presentation_1 = require("../../run/run-once-cycle/presentation");
const auth_message_sanitizer_1 = require("../auth-message-sanitizer");
const check_names_1 = require("./check-names");
async function collectAuthDoctorChecks(input) {
    const locale = input.locale ?? catalog_1.DEFAULT_APP_LOCALE;
    const profilesByProvider = groupAuthProfilesByProvider(input.authProfiles);
    const configuredWorkerProviders = (0, control_plane_config_1.getConfiguredBuiltInWorkers)(input.config);
    const configuredWorkers = new Set(configuredWorkerProviders);
    const stateByProfileId = new Map(input.authProfileStates.map((state) => [state.profileId, state]));
    const availabilityByProfileId = new Map((await Promise.all(input.authProfiles.map(async (profile) => [profile.id, await (0, availability_1.getSavedAuthAvailability)(profile)]))).map(([profileId, availability]) => [profileId, availability]));
    const checks = [
        await input.authProvider.checkRepositoryHostSession(input.config.repositoryHost),
        await input.authProvider.checkTicketTrackerSession(input.config.ticketTracker),
        ...(await Promise.all(configuredWorkerProviders.map((worker) => checkConfiguredWorker(worker, profilesByProvider.get(worker) ?? [], stateByProfileId, availabilityByProfileId, locale)))),
        ...(await Promise.all(input.authProfiles.map((profile) => checkStoredAuthProfile(profile, configuredWorkers.has((0, store_1.getAuthProfileProvider)(profile))
            ? [(0, store_1.getAuthProfileProvider)(profile)]
            : [], stateByProfileId, availabilityByProfileId.get(profile.id) ?? {
            available: false,
            reason: "missing_managed_sign_in_data",
        }, locale)))).flat(),
    ];
    return checks;
}
function formatWorkerLabel(worker) {
    return (0, store_1.formatAuthProvider)(worker);
}
function groupAuthProfilesByProvider(profiles) {
    const grouped = new Map();
    for (const profile of profiles) {
        const provider = (0, store_1.getAuthProfileProvider)(profile);
        const existing = grouped.get(provider);
        if (existing) {
            existing.push(profile);
            continue;
        }
        grouped.set(provider, [profile]);
    }
    return grouped;
}
async function checkConfiguredWorker(worker, profiles, stateByProfileId, availabilityByProfileId, locale) {
    const binaryCheck = await checkBinary(worker, locale);
    if (binaryCheck.status === "fail") {
        return {
            name: (0, check_names_1.getDoctorProviderCheckName)(formatWorkerLabel(worker), locale),
            status: "fail",
            message: binaryCheck.message,
        };
    }
    const providerProfiles = profiles.filter((profile) => (0, store_1.getAuthProfileProvider)(profile) === worker);
    const compatibleProfiles = providerProfiles.filter((profile) => (0, store_1.supportsWorkerAuthProfile)(worker, profile));
    if (compatibleProfiles.length === 0) {
        return {
            name: (0, check_names_1.getDoctorProviderCheckName)(formatWorkerLabel(worker), locale),
            status: "fail",
            message: (0, catalog_1.translate)(locale, "doctor.auth.noSignInsConfigured", {
                provider: formatWorkerLabel(worker),
            }),
        };
    }
    const availableProfiles = compatibleProfiles.filter((profile) => {
        const state = stateByProfileId.get(profile.id);
        return (availabilityByProfileId.get(profile.id)?.available &&
            !(state && (0, kind_1.isAuthProfileInvalid)(state)));
    });
    if (availableProfiles.length === 0) {
        return {
            name: (0, check_names_1.getDoctorProviderCheckName)(formatWorkerLabel(worker), locale),
            status: "fail",
            message: (0, catalog_1.translate)(locale, "doctor.auth.noWorkingSignInsConfigured", {
                provider: formatWorkerLabel(worker),
            }),
        };
    }
    const unavailableProfiles = compatibleProfiles.filter((profile) => {
        const state = stateByProfileId.get(profile.id);
        return (!availabilityByProfileId.get(profile.id)?.available ||
            Boolean(state && (0, kind_1.isAuthProfileInvalid)(state)));
    });
    if (unavailableProfiles.length > 0) {
        return {
            name: (0, check_names_1.getDoctorProviderCheckName)(formatWorkerLabel(worker), locale),
            status: "warning",
            message: (0, catalog_1.translate)(locale, "doctor.auth.availableAndUnavailable", {
                provider: formatWorkerLabel(worker),
                available: availableProfiles
                    .map((profile) => (0, presentation_1.renderSavedAuthLabelInCollection)(profile, providerProfiles, locale))
                    .join(", "),
                unavailable: unavailableProfiles
                    .map((profile) => (0, presentation_1.renderSavedAuthLabelInCollection)(profile, providerProfiles, locale))
                    .join(", "),
            }),
        };
    }
    return {
        name: (0, check_names_1.getDoctorProviderCheckName)(formatWorkerLabel(worker), locale),
        status: "ok",
        message: (0, catalog_1.translate)(locale, "doctor.auth.usesSignIns", {
            provider: formatWorkerLabel(worker),
            signIns: compatibleProfiles
                .map((profile) => (0, presentation_1.renderSavedAuthLabelInCollection)(profile, providerProfiles, locale))
                .join(", "),
        }),
    };
}
async function checkStoredAuthProfile(profile, owners, stateByProfileId, availability, locale) {
    const state = stateByProfileId.get(profile.id);
    if (state && (0, kind_1.isAuthProfileInvalid)(state)) {
        const label = (0, presentation_1.renderSavedAuthLabel)(profile, locale);
        const usage = renderAuthProfileUsage(owners, locale);
        const reason = state.lastReason
            ? (0, catalog_1.translate)(locale, "doctor.auth.profileAuthInvalidReason", {
                reason: (0, auth_message_sanitizer_1.sanitizeAuthMessage)(state.lastReason, locale),
            })
            : "";
        return [
            {
                name: (0, check_names_1.getDoctorSignInCheckName)(label, locale),
                status: "warning",
                message: (0, catalog_1.translate)(locale, "doctor.auth.profileAuthInvalid", {
                    label,
                    usage,
                }) +
                    reason +
                    (0, catalog_1.translate)(locale, "doctor.auth.profileAuthInvalidRecovery"),
            },
        ];
    }
    const incompatibleOwners = owners.filter((owner) => !(0, store_1.supportsWorkerAuthProfile)(owner, profile));
    if (incompatibleOwners.length > 0) {
        return [
            {
                name: (0, check_names_1.getDoctorSignInCheckName)((0, presentation_1.renderSavedAuthLabel)(profile, locale), locale),
                status: "fail",
                message: (0, catalog_1.translate)(locale, "doctor.auth.profileIncompatible", {
                    label: (0, presentation_1.renderSavedAuthLabel)(profile, locale),
                    providers: incompatibleOwners
                        .map((owner) => formatWorkerLabel(owner))
                        .join(", "),
                }),
            },
            buildCooldownCheck(profile, stateByProfileId, locale),
        ];
    }
    if (availability.available) {
        return [
            {
                name: (0, check_names_1.getDoctorSignInCheckName)((0, presentation_1.renderSavedAuthLabel)(profile, locale), locale),
                status: "ok",
                message: (0, catalog_1.translate)(locale, "doctor.auth.profileAvailable", {
                    label: (0, presentation_1.renderSavedAuthLabel)(profile, locale),
                    usage: renderAuthProfileUsage(owners, locale),
                }),
            },
            buildCooldownCheck(profile, stateByProfileId, locale),
        ];
    }
    if (owners.length === 0) {
        return [];
    }
    const message = renderUnavailableAuthProfileMessage(profile, owners, availability, locale);
    return [
        {
            name: (0, check_names_1.getDoctorSignInCheckName)((0, presentation_1.renderSavedAuthLabel)(profile, locale), locale),
            status: "warning",
            message,
        },
        buildCooldownCheck(profile, stateByProfileId, locale),
    ];
}
function renderUnavailableAuthProfileMessage(profile, owners, availability, locale) {
    const label = (0, presentation_1.renderSavedAuthLabel)(profile, locale);
    const usage = renderAuthProfileUsage(owners, locale);
    switch (availability.reason) {
        case "missing_env_var":
            return (0, catalog_1.translate)(locale, "doctor.auth.profileMissingEnv", {
                label,
                envVarName: availability.envVarName ?? "",
                usage,
            });
        case "missing_managed_sign_in_data":
            return (0, catalog_1.translate)(locale, "doctor.auth.profileMissingManaged", {
                label,
                usage,
            });
        case "missing_stored_credential":
            return (0, catalog_1.translate)(locale, "doctor.auth.profileMissingStoredCredential", {
                label,
                usage,
            });
        case "auth_unavailable":
            return (0, catalog_1.translate)(locale, "doctor.auth.profileAuthUnavailable", {
                label,
                usage,
            });
    }
}
function renderAuthProfileUsage(owners, locale) {
    if (owners.length === 0) {
        return (0, catalog_1.translate)(locale, "doctor.auth.profileUsage.none");
    }
    return (0, catalog_1.translate)(locale, "doctor.auth.profileUsage.selected", {
        providers: [
            ...new Set(owners.map((owner) => formatWorkerLabel(owner))),
        ].join(", "),
    });
}
function buildCooldownCheck(profile, stateByProfileId, locale) {
    const state = stateByProfileId.get(profile.id);
    if (state && (0, store_1.isAuthProfileOnCooldown)(state)) {
        return {
            name: (0, check_names_1.getDoctorCooldownCheckName)((0, presentation_1.renderSavedAuthLabel)(profile, locale), locale),
            status: "warning",
            message: (0, catalog_1.translate)(locale, "doctor.auth.cooldown.active", {
                cooldownUntil: state.cooldownUntil ?? "",
                reason: state.lastReason
                    ? (0, catalog_1.translate)(locale, "doctor.auth.cooldown.reason", {
                        reason: (0, auth_message_sanitizer_1.sanitizeAuthMessage)(state.lastReason, locale),
                    })
                    : "",
            }),
        };
    }
    return {
        name: (0, check_names_1.getDoctorCooldownCheckName)((0, presentation_1.renderSavedAuthLabel)(profile, locale), locale),
        status: "ok",
        message: (0, catalog_1.translate)(locale, "doctor.auth.cooldown.inactive"),
    };
}
async function checkBinary(binary, locale) {
    return (await (0, command_1.commandExists)(binary))
        ? {
            name: (0, check_names_1.getDoctorBinaryCheckName)(binary, locale),
            status: "ok",
            message: (0, catalog_1.translate)(locale, "doctor.auth.binary.installed", { binary }),
        }
        : {
            name: (0, check_names_1.getDoctorBinaryCheckName)(binary, locale),
            status: "fail",
            message: (0, catalog_1.translate)(locale, "doctor.auth.binary.notInstalled", {
                binary,
            }),
        };
}
