"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getOp = getOp;
exports.get = get;
exports.listMetricsOp = listMetricsOp;
exports.listMetrics = listMetrics;
exports.describeMetricOp = describeMetricOp;
exports.describeMetric = describeMetric;
const harper_logger_js_1 = __importDefault(require("../../utility/logging/harper_logger.js"));
const { forComponent } = harper_logger_js_1.default;
const hostnames_ts_1 = require("./hostnames.js");
const metadata_ts_1 = require("./metadata.js");
const hdbTerms_ts_1 = require("../../utility/hdbTerms.js");
const environmentManager_js_1 = require("../../utility/environment/environmentManager.js");
// default to one week time window for finding custom metrics
const defaultCustomMetricWindow = 1000 * 60 * 60 * 24 * 7;
const log = forComponent('analytics').conditional;
async function lookupHostname(nodeId) {
    const result = await (0, hostnames_ts_1.getAnalyticsHostnameTable)().get(nodeId);
    if (result?.hostname)
        return result.hostname;
    if (nodeId === (0, hostnames_ts_1.stableNodeId)(server.hostname))
        return server.hostname;
    return undefined;
}
function isSelected(querySelect, attr) {
    return querySelect.length === 0 || querySelect.includes(attr);
}
function getOp(req) {
    log.trace?.('get_analytics request:', req);
    return get(req.metric, {
        getAttributes: req.get_attributes,
        startTime: req.start_time,
        endTime: req.end_time,
        coalesceTime: req.coalesce_time,
        additionalConditions: req.conditions,
    });
}
function conformCondition(condition) {
    if ('conditions' in condition) {
        return {
            ...condition,
            conditions: condition.conditions.map(conformCondition),
        };
    }
    return {
        attribute: condition.search_attribute ?? condition.attribute,
        comparator: condition.search_type ?? condition.comparator,
        value: condition.search_value ?? condition.value,
    };
}
async function* coalesceResults(results, window) {
    let coalesceId;
    for await (const result of results) {
        const id = result.id;
        if (!coalesceId) {
            coalesceId = id;
        }
        const delta = Math.abs(id - coalesceId);
        if (delta < window) {
            yield { ...result, id: coalesceId };
        }
        else {
            yield result;
            coalesceId = id;
        }
    }
}
async function get(metric, opts) {
    const { getAttributes, startTime, endTime, additionalConditions } = opts ?? {};
    const conditions = [{ attribute: 'metric', comparator: 'equals', value: metric }];
    if (additionalConditions) {
        conditions.push(...additionalConditions.map(conformCondition));
    }
    const select = getAttributes ?? [];
    // ensure we're always selecting id
    if (!isSelected(select, 'id')) {
        select.push('id');
    }
    if (startTime && endTime) {
        conditions.push({
            attribute: 'id',
            comparator: 'between',
            value: [startTime, endTime],
        });
    }
    else {
        if (startTime) {
            conditions.push({
                attribute: 'id',
                comparator: 'greater_than_equal',
                value: startTime,
            });
        }
        if (endTime) {
            conditions.push({
                attribute: 'id',
                comparator: 'less_than',
                value: endTime,
            });
        }
    }
    const request = { conditions, allowConditionsOnDynamicAttributes: true };
    if (select.length > 0) {
        request['select'] = select;
    }
    log.trace?.('get_analytics hdb_analytics.search request:', JSON.stringify(request));
    const searchResults = await databases.system.hdb_analytics.search(request);
    let results = searchResults.map(async (result) => {
        // remove nodeId from 'id' attr and resolve it to the actual hostname and
        // add back in as 'node' attr if selected
        const nodeId = result.id[1];
        result = { ...result, id: result.id[0] };
        if (isSelected(select, 'node')) {
            log.trace?.(`get_analytics lookup hostname for nodeId: ${nodeId}`);
            const hostname = await lookupHostname(nodeId);
            result['node'] = hostname ?? nodeId;
        }
        log.trace?.(`get_analytics result:`, JSON.stringify(result));
        return result;
    });
    if (opts?.coalesceTime) {
        // coalescing window is the aggregate period converted to milliseconds
        const window = (0, environmentManager_js_1.get)(hdbTerms_ts_1.CONFIG_PARAMS.ANALYTICS_AGGREGATEPERIOD) * 1000;
        results = coalesceResults(results, window);
    }
    return results;
}
function listMetricsOp(req) {
    return listMetrics(req.metric_types, req.custom_metrics_window);
}
async function listMetrics(metricTypes = ['builtin'], customWindow = defaultCustomMetricWindow) {
    let metrics = [];
    const builtins = Object.values(metadata_ts_1.METRIC);
    if (metricTypes.includes('builtin')) {
        metrics = builtins;
    }
    if (metricTypes.includes('custom')) {
        const oldestCustomId = Date.now() - customWindow;
        const conditions = [
            {
                attribute: 'id',
                comparator: 'greater_than',
                value: oldestCustomId,
            },
        ];
        const metricConditions = builtins.map((c) => {
            return {
                attribute: 'metric',
                comparator: 'not_equal',
                value: c,
            };
        });
        conditions.push(...metricConditions);
        const customMetricsSearch = {
            select: ['metric'],
            conditions: conditions,
        };
        const customMetrics = new Set();
        const searchResults = await databases.system.hdb_analytics.search(customMetricsSearch);
        for await (const record of searchResults) {
            customMetrics.add(record.metric);
        }
        metrics.push(...Array.from(customMetrics.values()));
    }
    return metrics;
}
function describeMetricOp(req) {
    return describeMetric(req.metric);
}
async function describeMetric(metric) {
    const lastEntrySearch = {
        conditions: [{ attribute: 'metric', comparator: 'equals', value: metric }],
        sort: {
            attribute: 'id',
            descending: true,
        },
        limit: 1,
    };
    const results = databases.system.hdb_analytics.search(lastEntrySearch);
    // node is a synthetic attribute, so make sure it's included
    const attributes = [{ name: 'node', type: 'string' }];
    for await (const result of results) {
        for (const attr in result) {
            attributes.push({ name: attr, type: typeof result[attr] });
        }
        const desc = {
            attributes,
        };
        log.trace?.('describe_metric result:', JSON.stringify(desc));
        return desc;
    }
    // if no results, return empty object
    return {};
}
//# sourceMappingURL=read.js.map