"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FeatureLifecycleService = exports.STAGE_ENTERED = void 0;
const types_1 = require("../../types");
const events_1 = __importDefault(require("events"));
exports.STAGE_ENTERED = 'STAGE_ENTERED';
class FeatureLifecycleService extends events_1.default {
    constructor({ eventStore, featureLifecycleStore, environmentStore, featureEnvironmentStore, }, { eventService, }, { flagResolver, eventBus, getLogger, }) {
        super();
        this.eventStore = eventStore;
        this.featureLifecycleStore = featureLifecycleStore;
        this.environmentStore = environmentStore;
        this.featureEnvironmentStore = featureEnvironmentStore;
        this.flagResolver = flagResolver;
        this.eventBus = eventBus;
        this.eventService = eventService;
        this.logger = getLogger('feature-lifecycle/feature-lifecycle-service.ts');
    }
    async checkEnabled(fn) {
        const enabled = this.flagResolver.isEnabled('featureLifecycle');
        if (enabled) {
            return fn();
        }
    }
    listen() {
        this.eventStore.on(types_1.FEATURE_CREATED, async (event) => {
            await this.checkEnabled(() => this.featureInitialized(event.featureName));
        });
        this.eventBus.on(types_1.CLIENT_METRICS, async (event) => {
            if (event.environment) {
                const features = Object.keys(event.bucket.toggles);
                const environment = event.environment;
                await this.checkEnabled(() => this.featuresReceivedMetrics(features, environment));
            }
        });
        this.eventStore.on(types_1.FEATURE_ARCHIVED, async (event) => {
            await this.checkEnabled(() => this.featureArchived(event.featureName));
        });
        this.eventStore.on(types_1.FEATURE_REVIVED, async (event) => {
            await this.checkEnabled(() => this.featureRevived(event.featureName));
        });
    }
    async getFeatureLifecycle(feature) {
        return this.featureLifecycleStore.get(feature);
    }
    async featureInitialized(feature) {
        await this.featureLifecycleStore.insert([
            { feature, stage: 'initial' },
        ]);
        this.emit(exports.STAGE_ENTERED, { stage: 'initial' });
    }
    async stageReceivedMetrics(features, stage) {
        await this.featureLifecycleStore.insert(features.map((feature) => ({ feature, stage })));
        this.emit(exports.STAGE_ENTERED, { stage });
    }
    async featuresReceivedMetrics(features, environment) {
        try {
            const env = await this.environmentStore.get(environment);
            if (!env) {
                return;
            }
            await this.stageReceivedMetrics(features, 'pre-live');
            if (env.type === 'production') {
                const featureEnv = await this.featureEnvironmentStore.getAllByFeatures(features, env.name);
                const enabledFeatures = featureEnv
                    .filter((feature) => feature.enabled)
                    .map((feature) => feature.featureName);
                await this.stageReceivedMetrics(enabledFeatures, 'live');
            }
        }
        catch (e) {
            this.logger.warn(`Error handling ${features.length} metrics in ${environment}`, e);
        }
    }
    async featureCompleted(feature, auditUser) {
        await this.featureLifecycleStore.insert([
            {
                feature,
                stage: 'completed',
            },
        ]);
        await this.eventService.storeEvent(new types_1.FeatureCompletedEvent({
            featureName: feature,
            auditUser,
        }));
    }
    async featureUnCompleted(feature, auditUser) {
        await this.featureLifecycleStore.deleteStage({
            feature,
            stage: 'completed',
        });
        await this.eventService.storeEvent(new types_1.FeatureUncompletedEvent({
            featureName: feature,
            auditUser,
        }));
    }
    async featureArchived(feature) {
        await this.featureLifecycleStore.insert([
            { feature, stage: 'archived' },
        ]);
        this.emit(exports.STAGE_ENTERED, { stage: 'archived' });
    }
    async featureRevived(feature) {
        await this.featureLifecycleStore.delete(feature);
        await this.featureInitialized(feature);
    }
}
exports.FeatureLifecycleService = FeatureLifecycleService;
//# sourceMappingURL=feature-lifecycle-service.js.map