import { ZWaveError, ZWaveErrorCodes } from "@zwave-js/core";
import { ObjectKeyMap } from "@zwave-js/shared";
import { isArray } from "alcalzone-shared/typeguards";
import { evaluate } from "../Logic.js";
import { throwInvalidConfig } from "../utils_safe.js";
export function isConditionalItem(val) {
    // Conditional items must be objects or classes
    if (typeof val !== "object" || val == undefined)
        return false;
    // Conditional items may have a string-valued condition
    if (typeof val.condition !== "string"
        && typeof val.condition !== "undefined") {
        return false;
    }
    // Conditional items must have an evaluateCondition method
    if (typeof val.evaluateCondition !== "function")
        return false;
    return true;
}
/** Checks if a given condition applies for the given device ID */
export function conditionApplies(self, deviceId) {
    // No condition? Always applies
    if (!self.condition)
        return true;
    // No device ID? Always applies
    if (!deviceId)
        return true;
    try {
        return !!evaluate(self.condition, deviceId);
    }
    catch {
        throw new ZWaveError(`Invalid condition "${self.condition}"!`, ZWaveErrorCodes.Config_Invalid);
    }
}
export function validateCondition(filename, definition, errorPrefix) {
    if (definition.$if != undefined && typeof definition.$if !== "string") {
        throwInvalidConfig("devices", `packages/config/config/devices/${filename}:
${errorPrefix} invalid $if condition`);
    }
}
/**
 * Recursively evaluates the given conditional item. By default, arrays are collapsed to the first applicable item.
 */
export function evaluateDeep(obj, deviceId, preserveArray = false) {
    if (obj == undefined) {
        return obj;
    }
    else if (isArray(obj)) {
        if (preserveArray) {
            // Evaluate all array entries and return the ones that passed
            return obj
                .map((item) => evaluateDeep(item, deviceId, true))
                .filter((o) => o != undefined);
        }
        else {
            // Return the first matching array entry
            for (const item of obj) {
                const evaluated = evaluateDeep(item, deviceId, false);
                if (evaluated != undefined)
                    return evaluated;
            }
        }
    }
    else if (obj instanceof Map) {
        const ret = new Map();
        for (const [key, val] of obj) {
            // In maps only take the first possible value for each entry
            const evaluated = evaluateDeep(val, deviceId, false);
            if (evaluated != undefined) {
                ret.set(key, evaluated);
                continue;
            }
        }
        if (ret.size > 0)
            return ret;
    }
    else if (obj instanceof ObjectKeyMap) {
        const ret = new ObjectKeyMap();
        for (const [key, val] of obj) {
            // In maps only take the first possible value for each entry
            const evaluated = evaluateDeep(val, deviceId, false);
            if (evaluated != undefined) {
                ret.set(key, evaluated);
                continue;
            }
        }
        if (ret.size > 0)
            return ret;
    }
    else if (isConditionalItem(obj)) {
        // Evaluate the condition for simple items
        return obj.evaluateCondition(deviceId);
    }
    else {
        // Simply return non-conditional items
        return obj;
    }
}
//# sourceMappingURL=ConditionalItem.js.map