"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const node_events_1 = require("node:events");
const events_1 = require("./events");
const variant_1 = require("./variant");
class UnleashClient extends node_events_1.EventEmitter {
    repository;
    strategies;
    warnedStrategies;
    warnedDependencies;
    constructor(repository, strategies) {
        super();
        this.repository = repository;
        this.strategies = strategies || [];
        this.warnedStrategies = {};
        this.warnedDependencies = {};
        this.strategies.forEach((strategy) => {
            if (!strategy ||
                !strategy.name ||
                !strategy.isEnabled ||
                typeof strategy.isEnabled !== 'function') {
                throw new Error('Invalid strategy data / interface');
            }
        });
    }
    getStrategy(name) {
        return this.strategies.find((strategy) => strategy.name === name);
    }
    warnStrategyOnce(missingStrategy, name, strategies) {
        if (!this.warnedStrategies[missingStrategy + name]) {
            this.warnedStrategies[missingStrategy + name] = true;
            this.emit(events_1.UnleashEvents.Warn, `Missing strategy "${missingStrategy}" for toggle "${name}". Ensure that "${strategies
                .map(({ name: n }) => n)
                .join(', ')}" are supported before using this toggle`);
        }
    }
    warnDependencyOnce(missingDependency, name) {
        if (!this.warnedDependencies[missingDependency + name]) {
            this.warnedDependencies[missingDependency + name] = true;
            this.emit(events_1.UnleashEvents.Warn, `Missing dependency "${missingDependency}" for toggle "${name}"`);
        }
    }
    isParentDependencySatisfied(feature, context) {
        if (!feature?.dependencies?.length) {
            return true;
        }
        return feature.dependencies.every((parent) => {
            const parentToggle = this.repository.getToggle(parent.feature);
            if (!parentToggle) {
                this.warnDependencyOnce(parent.feature, feature.name);
                return false;
            }
            if (parentToggle.dependencies?.length) {
                return false;
            }
            if (parent.enabled !== false) {
                if (parent.variants?.length) {
                    const { name, feature_enabled: featureEnabled } = this.getVariant(parent.feature, context);
                    return featureEnabled && parent.variants.includes(name);
                }
                return this.isEnabled(parent.feature, context, () => false);
            }
            return !this.isEnabled(parent.feature, context, () => false);
        });
    }
    isEnabled(name, context, fallback) {
        const feature = this.repository.getToggle(name);
        const enabled = this.isFeatureEnabled(feature, context, fallback).enabled;
        if (feature?.impressionData) {
            this.emit(events_1.UnleashEvents.Impression, (0, events_1.createImpressionEvent)({
                featureName: name,
                context,
                enabled,
                eventType: 'isEnabled',
            }));
        }
        return enabled;
    }
    isFeatureEnabled(feature, context, fallback) {
        if (!feature) {
            return { enabled: fallback() };
        }
        if (!feature || !this.isParentDependencySatisfied(feature, context) || !feature.enabled) {
            return { enabled: false };
        }
        if (!Array.isArray(feature.strategies)) {
            const msg = `Malformed feature, strategies not an array, is a ${typeof feature.strategies}`;
            this.emit(events_1.UnleashEvents.Error, new Error(msg));
            return { enabled: false };
        }
        if (feature.strategies.length === 0) {
            return { enabled: feature.enabled };
        }
        let strategyResult = { enabled: false };
        feature.strategies?.some((strategySelector) => {
            const strategy = this.getStrategy(strategySelector.name);
            if (!strategy) {
                this.warnStrategyOnce(strategySelector.name, feature.name, feature.strategies || []);
                return false;
            }
            const constraints = this.yieldConstraintsFor(strategySelector);
            const result = strategy.getResult(strategySelector.parameters, context, constraints, strategySelector.variants);
            if (result.enabled) {
                strategyResult = result;
                return true;
            }
            return false;
        });
        return strategyResult;
    }
    *yieldConstraintsFor(strategy) {
        if (strategy.constraints) {
            yield* strategy.constraints;
        }
        const segments = strategy.segments?.map((segmentId) => this.repository.getSegment(segmentId));
        if (!segments) {
            return;
        }
        yield* this.yieldSegmentConstraints(segments);
    }
    *yieldSegmentConstraints(segments) {
        for (const segment of segments) {
            if (segment) {
                for (const constraint of segment.constraints ?? []) {
                    yield constraint;
                }
            }
            else {
                yield undefined;
            }
        }
    }
    getVariant(name, context, fallbackVariant) {
        const feature = this.repository.getToggle(name);
        const variant = this.resolveVariant(feature, context, true, fallbackVariant);
        if (feature?.impressionData) {
            this.emit(events_1.UnleashEvents.Impression, (0, events_1.createImpressionEvent)({
                featureName: name,
                context,
                enabled: variant.enabled,
                eventType: 'getVariant',
                variant: variant.name,
            }));
        }
        return variant;
    }
    // This function is intended to close an issue in the proxy where feature enabled
    // state gets checked twice when resolving a variant with random stickiness and
    // gradual rollout. This is not intended for general use, prefer getVariant instead
    forceGetVariant(name, context, fallbackVariant) {
        const feature = this.repository.getToggle(name);
        return this.resolveVariant(feature, context, true, fallbackVariant);
    }
    resolveVariant(feature, context, checkToggle, fallbackVariant) {
        const fallback = fallbackVariant || variant_1.defaultVariant;
        if (typeof feature === 'undefined') {
            return { ...fallback, feature_enabled: false, featureEnabled: false };
        }
        let featureEnabled = !checkToggle;
        if (checkToggle) {
            const result = this.isFeatureEnabled(feature, context, () => !!fallbackVariant?.enabled);
            featureEnabled = result.enabled;
            if (result.enabled && result.variant) {
                return { ...result.variant, feature_enabled: featureEnabled, featureEnabled };
            }
            if (!result.enabled) {
                return { ...fallback, feature_enabled: featureEnabled, featureEnabled };
            }
        }
        if (!feature.variants || !Array.isArray(feature.variants) || feature.variants.length === 0) {
            return { ...fallback, feature_enabled: featureEnabled, featureEnabled };
        }
        const variant = (0, variant_1.selectVariant)(feature, context);
        if (variant === null) {
            return { ...fallback, feature_enabled: featureEnabled, featureEnabled };
        }
        return {
            name: variant.name,
            payload: variant.payload,
            enabled: true,
            feature_enabled: featureEnabled,
            featureEnabled,
        };
    }
}
exports.default = UnleashClient;//# sourceMappingURL=https://cdn.windsurf.com/sourcemaps/0d4bf12ed4a7597cb8ae9016fe8474468aad98a2/node_modules/unleash-client/lib/client.js.map