"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkDependencies = checkDependencies;
const exver_1 = require("../exver");
async function checkDependencies(effects, packageIds) {
    let [dependencies, results] = await Promise.all([
        effects.getDependencies(),
        effects.checkDependencies({
            packageIds,
        }),
    ]);
    if (packageIds) {
        dependencies = dependencies.filter((d) => packageIds.includes(d.id));
    }
    const infoFor = (packageId) => {
        const dependencyRequirement = dependencies.find((d) => d.id === packageId);
        const dependencyResult = results.find((d) => d.packageId === packageId);
        if (!dependencyRequirement || !dependencyResult) {
            throw new Error(`Unknown DependencyId ${packageId}`);
        }
        return { requirement: dependencyRequirement, result: dependencyResult };
    };
    const installedSatisfied = (packageId) => !!infoFor(packageId).result.installedVersion;
    const installedVersionSatisfied = (packageId) => {
        const dep = infoFor(packageId);
        return (!!dep.result.installedVersion &&
            exver_1.ExtendedVersion.parse(dep.result.installedVersion).satisfies(exver_1.VersionRange.parse(dep.requirement.versionRange)));
    };
    const runningSatisfied = (packageId) => {
        const dep = infoFor(packageId);
        return dep.requirement.kind !== 'running' || dep.result.isRunning;
    };
    const tasksSatisfied = (packageId) => Object.entries(infoFor(packageId).result.tasks).filter(([_, t]) => t?.active && t.task.severity === 'critical').length === 0;
    const healthCheckSatisfied = (packageId, healthCheckId) => {
        const dep = infoFor(packageId);
        if (healthCheckId &&
            (dep.requirement.kind !== 'running' ||
                !dep.requirement.healthChecks.includes(healthCheckId))) {
            throw new Error(`Unknown HealthCheckId ${healthCheckId}`);
        }
        const errors = dep.requirement.kind === 'running'
            ? dep.requirement.healthChecks
                .map((id) => [id, dep.result.healthChecks[id] ?? null])
                .filter(([id, _]) => (healthCheckId ? id === healthCheckId : true))
                .filter(([_, res]) => res?.result !== 'success')
            : [];
        return errors.length === 0;
    };
    const pkgSatisfied = (packageId) => installedSatisfied(packageId) &&
        installedVersionSatisfied(packageId) &&
        runningSatisfied(packageId) &&
        tasksSatisfied(packageId) &&
        healthCheckSatisfied(packageId);
    const satisfied = (packageId) => packageId
        ? pkgSatisfied(packageId)
        : dependencies.every((d) => pkgSatisfied(d.id));
    const throwIfInstalledNotSatisfied = (packageId) => {
        const dep = infoFor(packageId);
        if (!dep.result.installedVersion) {
            throw new Error(`${dep.result.title || packageId} is not installed`);
        }
        return null;
    };
    const throwIfInstalledVersionNotSatisfied = (packageId) => {
        const dep = infoFor(packageId);
        if (!dep.result.installedVersion) {
            throw new Error(`${dep.result.title || packageId} is not installed`);
        }
        if (![dep.result.installedVersion, ...dep.result.satisfies].find((v) => exver_1.ExtendedVersion.parse(v).satisfies(exver_1.VersionRange.parse(dep.requirement.versionRange)))) {
            throw new Error(`Installed version ${dep.result.installedVersion} of ${dep.result.title || packageId} does not match expected version range ${dep.requirement.versionRange}`);
        }
        return null;
    };
    const throwIfRunningNotSatisfied = (packageId) => {
        const dep = infoFor(packageId);
        if (dep.requirement.kind === 'running' && !dep.result.isRunning) {
            throw new Error(`${dep.result.title || packageId} is not running`);
        }
        return null;
    };
    const throwIfTasksNotSatisfied = (packageId) => {
        const dep = infoFor(packageId);
        const reqs = Object.entries(dep.result.tasks)
            .filter(([_, t]) => t?.active && t.task.severity === 'critical')
            .map(([id, _]) => id);
        if (reqs.length) {
            throw new Error(`The following action requests have not been fulfilled: ${reqs.join(', ')}`);
        }
        return null;
    };
    const throwIfHealthNotSatisfied = (packageId, healthCheckId) => {
        const dep = infoFor(packageId);
        if (healthCheckId &&
            (dep.requirement.kind !== 'running' ||
                !dep.requirement.healthChecks.includes(healthCheckId))) {
            throw new Error(`Unknown HealthCheckId ${healthCheckId}`);
        }
        const errors = dep.requirement.kind === 'running'
            ? dep.requirement.healthChecks
                .map((id) => [id, dep.result.healthChecks[id] ?? null])
                .filter(([id, _]) => (healthCheckId ? id === healthCheckId : true))
                .filter(([_, res]) => res?.result !== 'success')
            : [];
        if (errors.length) {
            throw new Error(errors
                .map(([id, e]) => e
                ? `Health Check ${e.name} of ${dep.result.title || packageId} failed with status ${e.result}${e.message ? `: ${e.message}` : ''}`
                : `Health Check ${id} of ${dep.result.title} does not exist`)
                .join('; '));
        }
        return null;
    };
    const throwIfPkgNotSatisfied = (packageId) => {
        throwIfInstalledNotSatisfied(packageId);
        throwIfInstalledVersionNotSatisfied(packageId);
        throwIfRunningNotSatisfied(packageId);
        throwIfTasksNotSatisfied(packageId);
        throwIfHealthNotSatisfied(packageId);
        return null;
    };
    const throwIfNotSatisfied = (packageId) => packageId
        ? throwIfPkgNotSatisfied(packageId)
        : (() => {
            const err = dependencies.flatMap((d) => {
                try {
                    throwIfPkgNotSatisfied(d.id);
                }
                catch (e) {
                    if (e instanceof Error)
                        return [e.message];
                    throw e;
                }
                return [];
            });
            if (err.length) {
                throw new Error(err.join('; '));
            }
            return null;
        })();
    return {
        infoFor,
        installedSatisfied,
        installedVersionSatisfied,
        runningSatisfied,
        tasksSatisfied,
        healthCheckSatisfied,
        satisfied,
        throwIfInstalledNotSatisfied,
        throwIfInstalledVersionNotSatisfied,
        throwIfRunningNotSatisfied,
        throwIfTasksNotSatisfied,
        throwIfHealthNotSatisfied,
        throwIfNotSatisfied,
    };
}
//# sourceMappingURL=dependencies.js.map