"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("../../util");
const feature_toggle_store_1 = __importDefault(require("../feature-toggle/feature-toggle-store"));
const metrics_helper_1 = __importDefault(require("../../util/metrics-helper"));
const metric_events_1 = require("../../metric-events");
class ClientFeatureToggleReadModel {
    constructor(db, eventBus) {
        this.db = db;
        this.timer = (action) => metrics_helper_1.default.wrapTimer(eventBus, metric_events_1.DB_TIME, {
            store: 'client-feature-toggle-read-model',
            action,
        });
    }
    async getAll() {
        const stopTimer = this.timer(`getAll`);
        const selectColumns = [
            'features.name as name',
            'features.description as description',
            'features.type as type',
            'features.project as project',
            'features.stale as stale',
            'features.impression_data as impression_data',
            'fe.variants as variants',
            'fe.enabled as enabled',
            'fe.environment as environment',
            'fs.id as strategy_id',
            'fs.strategy_name as strategy_name',
            'fs.disabled as strategy_disabled',
            'fs.parameters as parameters',
            'fs.constraints as constraints',
            'fs.sort_order as sort_order',
            'fs.variants as strategy_variants',
            'segments.id as segment_id',
            'segments.constraints as segment_constraints',
            'df.parent as parent',
            'df.variants as parent_variants',
            'df.enabled as parent_enabled',
        ];
        let query = this.db('features')
            .modify(feature_toggle_store_1.default.filterByArchived, false)
            .leftJoin(this.db('feature_environments')
            .select('feature_name', 'enabled', 'environment', 'variants')
            .as('fe'), 'fe.feature_name', 'features.name')
            .leftJoin('feature_strategies as fs', function () {
            this.on('fs.feature_name', '=', 'features.name').andOn('fs.environment', '=', 'fe.environment');
        })
            .leftJoin('feature_strategy_segment as fss', `fss.feature_strategy_id`, `fs.id`)
            .leftJoin('segments', `segments.id`, `fss.segment_id`)
            .leftJoin('dependent_features as df', 'df.child', 'features.name')
            .where('fe.enabled', true);
        query = query.select(selectColumns);
        const rows = await query;
        stopTimer();
        const data = this.getAggregatedData(rows);
        return data;
    }
    getAggregatedData(rows) {
        const featureTogglesByEnv = {};
        rows.forEach((row) => {
            const environment = row.environment;
            const featureName = row.name;
            if (!featureTogglesByEnv[environment]) {
                featureTogglesByEnv[environment] = {};
            }
            if (!featureTogglesByEnv[environment][featureName]) {
                featureTogglesByEnv[environment][featureName] = {
                    name: featureName,
                    strategies: [],
                    variants: row.variants || [],
                    impressionData: row.impression_data,
                    enabled: !!row.enabled,
                    description: row.description,
                    project: row.project,
                    stale: row.stale,
                    type: row.type,
                };
            }
            const feature = featureTogglesByEnv[environment][featureName];
            if (row.parent) {
                feature.dependencies = feature.dependencies || [];
                feature.dependencies.push({
                    feature: row.parent,
                    enabled: row.parent_enabled,
                    ...(row.parent_enabled
                        ? { variants: row.parent_variants }
                        : {}),
                });
            }
            if (this.isUnseenStrategyRow(feature, row) &&
                !row.strategy_disabled) {
                feature.strategies = feature.strategies || [];
                feature.strategies.push(this.rowToStrategy(row));
            }
            if (row.segment_id) {
                this.addSegmentIdsToStrategy(feature, row);
            }
        });
        Object.values(featureTogglesByEnv).forEach((envFeatures) => {
            Object.values(envFeatures).forEach((feature) => {
                if (feature.strategies) {
                    feature.strategies = feature.strategies
                        .sort((a, b) => {
                        return (a.sortOrder || 0) - (b.sortOrder || 0);
                    })
                        .map(({ id, sortOrder, ...strategy }) => strategy);
                }
            });
        });
        return featureTogglesByEnv;
    }
    addSegmentIdsToStrategy(feature, row) {
        const strategy = feature.strategies?.find((s) => s?.id === row.strategy_id);
        if (!strategy) {
            return;
        }
        if (!strategy.segments) {
            strategy.segments = [];
        }
        strategy.segments.push(row.segment_id);
    }
    rowToStrategy(row) {
        const strategy = {
            id: row.strategy_id,
            name: row.strategy_name,
            title: row.strategy_title,
            constraints: row.constraints || [],
            parameters: (0, util_1.mapValues)(row.parameters || {}, util_1.ensureStringValue),
            sortOrder: row.sort_order,
        };
        strategy.variants = row.strategy_variants || [];
        return strategy;
    }
    isUnseenStrategyRow(feature, row) {
        return (row.strategy_id &&
            !feature.strategies?.find((s) => s?.id === row.strategy_id));
    }
}
exports.default = ClientFeatureToggleReadModel;
//# sourceMappingURL=client-feature-toggle-read-model.js.map