"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.editorToMetric = editorToMetric;
exports.buildWhereClause = buildWhereClause;
const tslib_1 = require("tslib");
/* eslint-disable @typescript-eslint/restrict-template-expressions */
const util_1 = require("../util");
const expressionRelationships_1 = require("../core/enums/expressionRelationships");
const metricVisibility_1 = require("../core/enums/metricVisibility");
/**
 * Transforms the IConfigurationValues into an object with IMetric and IMetricDisplayConfig to be saved on an entity or rendered in the ui.
 * @param values IConfigurationValues for the arcgis-hub-metric-card to use
 * @param metricId what should be the id of the transformed metric
 * @param entityInfo what should be the entityInfo of the transformed metric
 * @returns IMetricCardParams
 */
function editorToMetric(values = {
    displayType: "stat-card",
    metricId: undefined,
}, metricId, opts) {
    const { value, valueType, dynamicMetric } = values, config = tslib_1.__rest(values, ["value", "valueType", "dynamicMetric"]);
    const { layerId, itemId, field, statistic, serviceUrl, fieldType, sourceLink, sourceTitle, allowExpressionSet, expressionSet, legacyWhere, } = dynamicMetric || {};
    const { entityInfo, metricName } = opts || {};
    // create source
    const source = values.type === "dynamic"
        ? {
            type: "service-query",
            serviceUrl,
            layerId,
            field,
            statistic: statistic,
            where: legacyWhere
                ? legacyWhere
                : buildWhereClause(allowExpressionSet ? expressionSet : []),
        }
        : {
            type: "static-value",
            value,
            valueType,
        };
    // create metric
    const metric = {
        source,
        name: metricName || metricId,
        entityInfo: entityInfo || {
            id: undefined,
            name: undefined,
            type: undefined,
        }, // ensure entity info has id, name, type
        id: metricId,
    };
    delete config.itemId;
    // create card config
    const displayConfig = Object.assign(Object.assign({}, config), { displayType: config.displayType || "stat-card", visibility: config.visibility || metricVisibility_1.MetricVisibility.hidden, metricId,
        // dynamic metric values
        fieldType,
        itemId,
        expressionSet,
        allowExpressionSet,
        statistic, 
        // if we are in dynamic mode and have a link, then we use that link
        // otherwise we use manually input sourceLink on card config
        sourceLink: values.type === "dynamic" && sourceLink ? sourceLink : config.sourceLink, sourceTitle: values.type === "dynamic" && sourceTitle
            ? sourceTitle
            : config.sourceTitle, allowLink: values.type === "dynamic" ? config.allowDynamicLink : config.allowLink, type: values.type });
    return { metric, displayConfig };
}
/**
 * Constructs a where clause from a given expression set.
 *
 * @param {Array} fields the available fields for a given dataset
 * @param {Object} values the selected values
 *
 * @returns {string} returns a string for the where clause query
 *
 * NOTE: currently returns string as a MATCH and everything else as BETWEEN
 */
function buildWhereClause(expressionSet = []) {
    const whereClause = expressionSet
        .map((expression) => {
        const { field, values, relationship } = expression;
        const escape = (value) => {
            // Ensure that the value has a .replace method
            // We encountered a case where the value was an empty object (unclear how this happened)
            // and it caused the site to go into an infinite loop and crash. This is a safeguard.
            return value.replace && value.replace(/(['])/g, "$1$1"); // currently only handles single quotes
        };
        // if we don't have values or field, or if it is an "incomplete" expression, do not include
        if (!values || !values.length || !field || !field.name) {
            return false;
        }
        let clause;
        switch (field.type) {
            case "esriFieldTypeString":
                // used for migrating over the old "like" clauses
                clause =
                    relationship === expressionRelationships_1.ExpressionRelationships.LIKE
                        ? `${field.name} like '%${values[0]}%'`
                        : `(${field.name} IN (${values
                            .map((value) => `'${escape(value)}'`)
                            .join(", ")}))`;
                break;
            case "esriFieldTypeDate":
                // just the first bounding value
                if (typeof values[0] === "string") {
                    clause = `${field.name} >= timestamp '${escape(values[0])} 00:00:00'`;
                }
                // just the second bounding value
                if (typeof values[1] === "string") {
                    clause = `${field.name} <= timestamp '${escape(values[1])} 23:59:59'`;
                }
                // if we have both, rewrite clause
                if (typeof values[0] === "string" &&
                    typeof values[1] === "string") {
                    clause = `${field.name} >= timestamp '${escape(values[0])} 00:00:00' AND ${field.name} <= timestamp '${escape(values[1])} 23:59:59'`;
                }
                break;
            default:
                // just the first bounding value
                if (!(0, util_1.isNil)(values[0])) {
                    clause = `(${field.name}) >= ${values[0]}`;
                }
                // just the second bounding value
                if (!(0, util_1.isNil)(values[1])) {
                    clause = `(${field.name}) <= ${values[1]}`;
                }
                // if we have both, rewrite clause
                if (!(0, util_1.isNil)(values[0]) && !(0, util_1.isNil)(values[1])) {
                    clause = `(${field.name}) >= ${values[0]} AND (${field.name}) <= ${values[1]}`;
                }
                break;
        }
        return clause;
    })
        .filter(Boolean)
        .join(" AND ") || "1=1";
    return encodeURIComponent(whereClause);
}
//# sourceMappingURL=editorToMetric.js.map