import { getCCName, stripUndefined, } from "@zwave-js/core";
import { pick } from "@zwave-js/shared";
import { isArray, isObject } from "alcalzone-shared/typeguards";
import { throwInvalidConfig, tryParseCCId } from "../utils_safe.js";
import { conditionApplies } from "./ConditionalItem.js";
export class ConditionalCompatConfig {
    valueIdRegex = /^\$value\$\[.+\]$/;
    constructor(filename, definition) {
        this.condition = definition.$if;
        if (definition.queryOnWakeup != undefined) {
            if (!isArray(definition.queryOnWakeup)
                || !definition.queryOnWakeup.every((cmd) => isArray(cmd)
                    && cmd.length >= 2
                    && typeof cmd[0] === "string"
                    && typeof cmd[1] === "string"
                    && cmd
                        .slice(2)
                        .every((arg) => typeof arg === "string"
                        || typeof arg === "number"
                        || typeof arg === "boolean"))) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option queryOnWakeup`);
            }
            // Parse "smart" values into partial Value IDs
            this.queryOnWakeup = definition.queryOnWakeup.map((cmd) => cmd.map((arg) => {
                if (typeof arg === "string"
                    && this.valueIdRegex.test(arg)) {
                    const tuple = JSON.parse(arg.slice("$value$".length));
                    return {
                        property: tuple[0],
                        propertyKey: tuple[1],
                    };
                }
                return arg;
            }));
        }
        if (definition.disableAutoRefresh != undefined) {
            if (definition.disableAutoRefresh !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option disableAutoRefresh must be true or omitted`);
            }
            this.disableAutoRefresh = definition.disableAutoRefresh;
        }
        if (definition.disableCallbackFunctionTypeCheck != undefined) {
            if (!isArray(definition.disableCallbackFunctionTypeCheck)
                || !definition.disableCallbackFunctionTypeCheck.every((d) => typeof d === "number" && d % 1 === 0 && d > 0)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
when present, compat option disableCallbackFunctionTypeCheck msut be an array of positive integers`);
            }
            this.disableCallbackFunctionTypeCheck =
                definition.disableCallbackFunctionTypeCheck;
        }
        if (definition.disableStrictEntryControlDataValidation != undefined) {
            if (definition.disableStrictEntryControlDataValidation !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option disableStrictEntryControlDataValidation must be true or omitted`);
            }
            this.disableStrictEntryControlDataValidation =
                definition.disableStrictEntryControlDataValidation;
        }
        if (definition.disableStrictMeasurementValidation != undefined) {
            if (definition.disableStrictMeasurementValidation !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option disableStrictMeasurementValidation must be true or omitted`);
            }
            this.disableStrictMeasurementValidation =
                definition.disableStrictMeasurementValidation;
        }
        if (definition.encodeCCsUsingTargetVersion != undefined) {
            if (definition.encodeCCsUsingTargetVersion !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option encodeCCsUsingTargetVersion must be true or omitted`);
            }
            this.encodeCCsUsingTargetVersion =
                definition.encodeCCsUsingTargetVersion;
        }
        if (definition.forceNotificationIdleReset != undefined) {
            if (definition.forceNotificationIdleReset !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option forceNotificationIdleReset must be true or omitted`);
            }
            this.forceNotificationIdleReset =
                definition.forceNotificationIdleReset;
        }
        if (definition.forceSceneControllerGroupCount != undefined) {
            if (typeof definition.forceSceneControllerGroupCount !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option forceSceneControllerGroupCount must be a number!`);
            }
            if (definition.forceSceneControllerGroupCount < 0
                || definition.forceSceneControllerGroupCount > 255) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option forceSceneControllerGroupCount must be between 0 and 255!`);
            }
            this.forceSceneControllerGroupCount =
                definition.forceSceneControllerGroupCount;
        }
        if (definition.mapBasicReport != undefined) {
            if (!isBasicReportMapping(definition.mapBasicReport)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option mapBasicReport contains an invalid value`);
            }
            this.mapBasicReport = definition.mapBasicReport;
        }
        if (definition.mapBasicSet != undefined) {
            if (!isBasicSetMapping(definition.mapBasicSet)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option mapBasicSet contains an invalid value`);
            }
            this.mapBasicSet = definition.mapBasicSet;
        }
        if (definition.preserveRootApplicationCCValueIDs != undefined) {
            if (definition.preserveRootApplicationCCValueIDs !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option preserveRootApplicationCCValueIDs`);
            }
            this.preserveRootApplicationCCValueIDs =
                definition.preserveRootApplicationCCValueIDs;
        }
        if (definition.preserveEndpoints != undefined) {
            if (definition.preserveEndpoints !== "*"
                && !(isArray(definition.preserveEndpoints)
                    && definition.preserveEndpoints.every((d) => typeof d === "number" && d % 1 === 0 && d > 0))) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option preserveEndpoints must be "*" or an array of positive integers`);
            }
            this.preserveEndpoints = definition.preserveEndpoints;
        }
        if (definition.removeEndpoints != undefined) {
            if (definition.removeEndpoints !== "*"
                && !(isArray(definition.removeEndpoints)
                    && definition.removeEndpoints.every((d) => typeof d === "number" && d % 1 === 0 && d > 0))) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option removeEndpoints must be "*" or an array of positive integers`);
            }
            this.removeEndpoints = definition.removeEndpoints;
        }
        if (definition.skipConfigurationNameQuery != undefined) {
            if (definition.skipConfigurationNameQuery !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option skipConfigurationNameQuery`);
            }
            this.skipConfigurationNameQuery =
                definition.skipConfigurationNameQuery;
        }
        if (definition.skipConfigurationInfoQuery != undefined) {
            if (definition.skipConfigurationInfoQuery !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option skipConfigurationInfoQuery`);
            }
            this.skipConfigurationInfoQuery =
                definition.skipConfigurationInfoQuery;
        }
        if (definition.treatMultilevelSwitchSetAsEvent != undefined) {
            if (definition.treatMultilevelSwitchSetAsEvent !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option treatMultilevelSwitchSetAsEvent`);
            }
            this.treatMultilevelSwitchSetAsEvent =
                definition.treatMultilevelSwitchSetAsEvent;
        }
        if (definition.treatSetAsReport != undefined) {
            if (!(isArray(definition.treatSetAsReport)
                && definition.treatSetAsReport.every((d) => typeof d === "string"))) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option treatSetAsReport must be an array of strings`);
            }
            this.treatSetAsReport = new Set(definition.treatSetAsReport);
        }
        if (definition.treatDestinationEndpointAsSource != undefined) {
            if (definition.treatDestinationEndpointAsSource !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option treatDestinationEndpointAsSource`);
            }
            this.treatDestinationEndpointAsSource =
                definition.treatDestinationEndpointAsSource;
        }
        if (definition.useUTCInTimeParametersCC != undefined) {
            if (definition.useUTCInTimeParametersCC !== true) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option useUTCInTimeParametersCC must be true or omitted`);
            }
            this.useUTCInTimeParametersCC = definition.useUTCInTimeParametersCC;
        }
        if (definition.manualValueRefreshDelayMs != undefined) {
            if (typeof definition.manualValueRefreshDelayMs !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option manualValueRefreshDelayMs must be a number!`);
            }
            if (definition.manualValueRefreshDelayMs % 1 !== 0
                || definition.manualValueRefreshDelayMs < 0) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option manualValueRefreshDelayMs must be a non-negative integer!`);
            }
            this.manualValueRefreshDelayMs =
                definition.manualValueRefreshDelayMs;
        }
        if (definition.reportTimeout != undefined) {
            if (typeof definition.reportTimeout !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option reportTimeout must be a number!`);
            }
            if (definition.reportTimeout % 1 !== 0
                || definition.reportTimeout < 1000
                || definition.reportTimeout > 10000) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option reportTimeout must be an integer between 1000 and 10000!`);
            }
            this.reportTimeout = definition.reportTimeout;
        }
        if (definition.mapRootReportsToEndpoint != undefined) {
            if (typeof definition.mapRootReportsToEndpoint !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option mapRootReportsToEndpoint must be a number!`);
            }
            if (definition.mapRootReportsToEndpoint % 1 !== 0
                || definition.mapRootReportsToEndpoint < 1) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option mapRootReportsToEndpoint must be a positive integer!`);
            }
            this.mapRootReportsToEndpoint = definition.mapRootReportsToEndpoint;
        }
        if (definition.overrideFloatEncoding != undefined) {
            if (!isObject(definition.overrideFloatEncoding)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option overrideFloatEncoding`);
            }
            this.overrideFloatEncoding = {};
            if ("precision" in definition.overrideFloatEncoding) {
                if (typeof definition.overrideFloatEncoding.precision
                    != "number") {
                    throwInvalidConfig("devices", `config/devices/${filename}:
compat option overrideFloatEncoding.precision must be a number!`);
                }
                if (definition.overrideFloatEncoding.precision % 1 !== 0
                    || definition.overrideFloatEncoding.precision < 0) {
                    throwInvalidConfig("devices", `config/devices/${filename}:
compat option overrideFloatEncoding.precision must be a positive integer!`);
                }
                this.overrideFloatEncoding.precision =
                    definition.overrideFloatEncoding.precision;
            }
            if ("size" in definition.overrideFloatEncoding) {
                if (typeof definition.overrideFloatEncoding.size != "number") {
                    throwInvalidConfig("devices", `config/devices/${filename}:
compat option overrideFloatEncoding.size must be a number!`);
                }
                if (definition.overrideFloatEncoding.size % 1 !== 0
                    || definition.overrideFloatEncoding.size < 1
                    || definition.overrideFloatEncoding.size > 4) {
                    throwInvalidConfig("devices", `config/devices/${filename}:
compat option overrideFloatEncoding.size must be an integer between 1 and 4!`);
                }
                this.overrideFloatEncoding.size =
                    definition.overrideFloatEncoding.size;
            }
            if (Object.keys(this.overrideFloatEncoding).length === 0) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option overrideFloatEncoding: size and/or precision must be specified!`);
            }
        }
        if (definition.commandClasses != undefined) {
            if (!isObject(definition.commandClasses)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option commandClasses`);
            }
            if (definition.commandClasses.add != undefined) {
                if (!isObject(definition.commandClasses.add)) {
                    throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option commandClasses.add`);
                }
                else if (!Object.values(definition.commandClasses.add).every((v) => isObject(v))) {
                    throwInvalidConfig("devices", `config/devices/${filename}:
All values in compat option commandClasses.add must be objects`);
                }
                const addCCs = new Map();
                for (const [key, info] of Object.entries(definition.commandClasses.add)) {
                    // Parse the key into a CC ID
                    const cc = tryParseCCId(key);
                    if (cc == undefined) {
                        throwInvalidConfig("devices", `config/devices/${filename}:
Invalid Command Class "${key}" specified in compat option commandClasses.add!`);
                    }
                    addCCs.set(cc, new CompatAddCC(filename, info));
                }
                this.addCCs = addCCs;
            }
            if (definition.commandClasses.remove != undefined) {
                if (!isObject(definition.commandClasses.remove)) {
                    throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option commandClasses.remove`);
                }
                const removeCCs = new Map();
                for (const [key, info] of Object.entries(definition.commandClasses.remove)) {
                    // Parse the key into a CC ID
                    const cc = tryParseCCId(key);
                    if (cc == undefined) {
                        throwInvalidConfig("devices", `config/devices/${filename}:
Invalid Command Class "${key}" specified in compat option commandClasses.remove!`);
                    }
                    if (isObject(info) && "endpoints" in info) {
                        if (info.endpoints === "*"
                            || (isArray(info.endpoints)
                                && info.endpoints.every((i) => typeof i === "number"))) {
                            removeCCs.set(cc, info.endpoints);
                        }
                        else {
                            throwInvalidConfig("devices", `config/devices/${filename}:
Compat option commandClasses.remove has an invalid "endpoints" property. Only "*" and numeric arrays are allowed!`);
                        }
                    }
                    else {
                        throwInvalidConfig("devices", `config/devices/${filename}:
All values in compat option commandClasses.remove must be objects with an "endpoints" property!`);
                    }
                }
                this.removeCCs = removeCCs;
            }
        }
        if (definition.alarmMapping != undefined) {
            if (!isArray(definition.alarmMapping)
                || !definition.alarmMapping.every((m) => isObject(m))) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option alarmMapping must be an array where all items are objects!`);
            }
            this.alarmMapping = definition.alarmMapping.map((m, i) => new CompatMapAlarm(filename, m, i + 1));
        }
        if (definition.remapNotifications != undefined) {
            if (!isArray(definition.remapNotifications)
                || !definition.remapNotifications.every((m) => isObject(m))) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option remapNotifications must be an array where all items are objects!`);
            }
            this.remapNotifications = definition.remapNotifications
                .map((m, i) => new CompatRemapNotification(filename, m, i + 1));
        }
        if (definition.overrideQueries != undefined) {
            if (!isObject(definition.overrideQueries)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
compat option overrideQueries must be an object!`);
            }
            this.overrideQueries = new CompatOverrideQueries(filename, definition.overrideQueries);
        }
    }
    alarmMapping;
    remapNotifications;
    addCCs;
    removeCCs;
    disableAutoRefresh;
    disableStrictEntryControlDataValidation;
    disableStrictMeasurementValidation;
    disableCallbackFunctionTypeCheck;
    encodeCCsUsingTargetVersion;
    forceNotificationIdleReset;
    forceSceneControllerGroupCount;
    manualValueRefreshDelayMs;
    mapRootReportsToEndpoint;
    mapBasicReport;
    mapBasicSet;
    overrideFloatEncoding;
    overrideQueries;
    preserveRootApplicationCCValueIDs;
    preserveEndpoints;
    removeEndpoints;
    reportTimeout;
    skipConfigurationNameQuery;
    skipConfigurationInfoQuery;
    treatMultilevelSwitchSetAsEvent;
    treatSetAsReport;
    treatDestinationEndpointAsSource;
    useUTCInTimeParametersCC;
    queryOnWakeup;
    condition;
    evaluateCondition(deviceId) {
        if (!conditionApplies(this, deviceId))
            return;
        const ret = pick(this, [
            "alarmMapping",
            "remapNotifications",
            "addCCs",
            "removeCCs",
            "disableAutoRefresh",
            "disableCallbackFunctionTypeCheck",
            "disableStrictEntryControlDataValidation",
            "disableStrictMeasurementValidation",
            "encodeCCsUsingTargetVersion",
            "forceNotificationIdleReset",
            "forceSceneControllerGroupCount",
            "manualValueRefreshDelayMs",
            "mapBasicReport",
            "mapBasicSet",
            "mapRootReportsToEndpoint",
            "overrideFloatEncoding",
            "overrideQueries",
            "reportTimeout",
            "preserveRootApplicationCCValueIDs",
            "preserveEndpoints",
            "removeEndpoints",
            "skipConfigurationNameQuery",
            "skipConfigurationInfoQuery",
            "treatMultilevelSwitchSetAsEvent",
            "treatSetAsReport",
            "treatDestinationEndpointAsSource",
            "useUTCInTimeParametersCC",
            "queryOnWakeup",
        ]);
        return stripUndefined(ret);
    }
}
export class CompatAddCC {
    constructor(filename, definition) {
        const endpoints = new Map();
        const parseEndpointInfo = (endpoint, info) => {
            const parsed = {};
            if (info.isSupported != undefined) {
                if (typeof info.isSupported !== "boolean") {
                    throwInvalidConfig("devices", `config/devices/${filename}:
Property isSupported in compat option commandClasses.add, endpoint ${endpoint} must be a boolean!`);
                }
                else {
                    parsed.isSupported = info.isSupported;
                }
            }
            if (info.isControlled != undefined) {
                if (typeof info.isControlled !== "boolean") {
                    throwInvalidConfig("devices", `config/devices/${filename}:
Property isControlled in compat option commandClasses.add, endpoint ${endpoint} must be a boolean!`);
                }
                else {
                    parsed.isControlled = info.isControlled;
                }
            }
            if (info.secure != undefined) {
                if (typeof info.secure !== "boolean") {
                    throwInvalidConfig("devices", `config/devices/${filename}:
Property secure in compat option commandClasses.add, endpoint ${endpoint} must be a boolean!`);
                }
                else {
                    parsed.secure = info.secure;
                }
            }
            if (info.version != undefined) {
                if (typeof info.version !== "number") {
                    throwInvalidConfig("devices", `config/devices/${filename}:
Property version in compat option commandClasses.add, endpoint ${endpoint} must be a number!`);
                }
                else {
                    parsed.version = info.version;
                }
            }
            endpoints.set(endpoint, parsed);
        };
        // Parse root endpoint info if given
        if (definition.isSupported != undefined
            || definition.isControlled != undefined
            || definition.version != undefined
            || definition.secure != undefined) {
            // We have info for the root endpoint
            parseEndpointInfo(0, definition);
        }
        // Parse all other endpoints
        if (isObject(definition.endpoints)) {
            if (!Object.keys(definition.endpoints).every((k) => /^\d+$/.test(k))) {
                throwInvalidConfig("devices", `config/devices/${filename}:
invalid endpoint index in compat option commandClasses.add`);
            }
            else {
                for (const [ep, info] of Object.entries(definition.endpoints)) {
                    parseEndpointInfo(parseInt(ep), info);
                }
            }
        }
        this.endpoints = endpoints;
    }
    endpoints;
}
export class CompatMapAlarm {
    constructor(filename, definition, index) {
        if (!isObject(definition.from)) {
            throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option alarmMapping, mapping #${index}: property "from" must be an object!`);
        }
        else {
            if (typeof definition.from.alarmType !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option alarmMapping, mapping #${index}: property "from.alarmType" must be a number!`);
            }
            if (definition.from.alarmLevel != undefined
                && typeof definition.from.alarmLevel !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option alarmMapping, mapping #${index}: if property "from.alarmLevel" is given, it must be a number!`);
            }
        }
        if (!isObject(definition.to)) {
            throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option alarmMapping, mapping #${index}: property "to" must be an object!`);
        }
        else {
            if (typeof definition.to.notificationType !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option alarmMapping, mapping #${index}: property "to.notificationType" must be a number!`);
            }
            if (typeof definition.to.notificationEvent !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option alarmMapping, mapping #${index}: property "to.notificationEvent" must be a number!`);
            }
            if (definition.to.eventParameters != undefined) {
                if (!isObject(definition.to.eventParameters)) {
                    throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option alarmMapping, mapping #${index}: property "to.eventParameters" must be an object!`);
                }
                else {
                    for (const [key, val] of Object.entries(definition.to.eventParameters)) {
                        if (typeof val !== "number" && val !== "alarmLevel") {
                            throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option alarmMapping, mapping #${index}: property "to.eventParameters.${key}" must be a number or the literal "alarmLevel"!`);
                        }
                    }
                }
            }
        }
        this.from = pick(definition.from, ["alarmType", "alarmLevel"]);
        this.to = pick(definition.to, [
            "notificationType",
            "notificationEvent",
            "eventParameters",
        ]);
    }
    from;
    to;
}
export class CompatRemapNotification {
    constructor(filename, definition, index) {
        if (!isObject(definition.from)) {
            throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option remapNotifications, mapping #${index}: property "from" must be an object!`);
        }
        else {
            if (typeof definition.from.notificationType !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option remapNotifications, mapping #${index}: property "from.notificationType" must be a number!`);
            }
            if (typeof definition.from.notificationEvent !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option remapNotifications, mapping #${index}: property "from.notificationEvent" must be a number!`);
            }
        }
        this.from = pick(definition.from, [
            "notificationType",
            "notificationEvent",
        ]);
        const validateToObject = (obj, label) => {
            if (!isObject(obj)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option remapNotifications, mapping #${index}: ${label} must be an object!`);
            }
            if (typeof obj.notificationType !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option remapNotifications, mapping #${index}: ${label} must have a numeric "notificationType"!`);
            }
            if (typeof obj.notificationEvent !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option remapNotifications, mapping #${index}: ${label} must have a numeric "notificationEvent"!`);
            }
        };
        const validateTargetArray = (arr, label) => {
            if (!isArray(arr) || arr.length === 0) {
                throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option remapNotifications, mapping #${index}: property "${label}" must be a non-empty array of objects!`);
            }
            for (let j = 0; j < arr.length; j++) {
                validateToObject(arr[j], `"${label}[${j}]"`);
            }
        };
        if (definition.to != undefined) {
            validateToObject(definition.to, `property "to"`);
            this.action = {
                type: "remap",
                to: pick(definition.to, [
                    "notificationType",
                    "notificationEvent",
                ]),
            };
        }
        else if (definition.clear != undefined) {
            validateTargetArray(definition.clear, "clear");
            this.action = {
                type: "clear",
                targets: definition.clear.map((target) => pick(target, ["notificationType", "notificationEvent"])),
            };
        }
        else if (definition.idle != undefined) {
            validateTargetArray(definition.idle, "idle");
            this.action = {
                type: "idle",
                targets: definition.idle.map((target) => pick(target, ["notificationType", "notificationEvent"])),
            };
        }
        else {
            throwInvalidConfig("devices", `config/devices/${filename}:
error in compat option remapNotifications, mapping #${index}: exactly one of "to", "clear", or "idle" must be defined!`);
        }
    }
    from;
    action;
}
export class CompatOverrideQueries {
    constructor(filename, definition) {
        const overrides = new Map();
        const parseOverride = (cc, info) => {
            if (typeof info.method !== "string") {
                throwInvalidConfig("devices", `config/devices/${filename}:
Property "method" in compat option overrideQueries, CC ${getCCName(cc)} must be a string!`);
            }
            else if (info.matchArgs != undefined
                && !isArray(info.matchArgs)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
Property "matchArgs" in compat option overrideQueries, CC ${getCCName(cc)} must be an array!`);
            }
            else if (!("result" in info)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
Property "result" is missing in in compat option overrideQueries, CC ${getCCName(cc)}!`);
            }
            else if (info.endpoint != undefined
                && typeof info.endpoint !== "number") {
                throwInvalidConfig("devices", `config/devices/${filename}:
Property "endpoint" in compat option overrideQueries, CC ${getCCName(cc)} must be a number!`);
            }
            else if (info.persistValues && !isObject(info.persistValues)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
Property "persistValues" in compat option overrideQueries, CC ${getCCName(cc)} must be an object!`);
            }
            else if (info.extendMetadata && !isObject(info.extendMetadata)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
Property "extendMetadata" in compat option overrideQueries, CC ${getCCName(cc)} must be an object!`);
            }
            return {
                endpoint: info.endpoint,
                method: info.method,
                matchArgs: info.matchArgs,
                result: info.result,
                persistValues: info.persistValues,
                extendMetadata: info.extendMetadata,
            };
        };
        for (const [key, value] of Object.entries(definition)) {
            // Parse the key into a CC ID
            const cc = tryParseCCId(key);
            if (cc == undefined) {
                throwInvalidConfig("devices", `config/devices/${filename}:
Invalid Command Class "${key}" specified in compat option overrideQueries!`);
            }
            let overrideDefinitions;
            if (isObject(value)) {
                overrideDefinitions = [value];
            }
            else if (!isArray(value)) {
                throwInvalidConfig("devices", `config/devices/${filename}:
Property "${key}" in compat option overrideQueries must be a single override object or an array thereof!`);
            }
            else {
                overrideDefinitions = value;
            }
            overrides.set(cc, overrideDefinitions.map((info) => parseOverride(cc, info)));
        }
        this.overrides = overrides;
    }
    // CC -> endpoint -> queries
    overrides;
    hasOverride(ccId) {
        return this.overrides.has(ccId);
    }
    matchOverride(cc, endpointIndex, method, args) {
        const queries = this.overrides.get(cc);
        if (!queries)
            return undefined;
        for (const query of queries) {
            if ((query.endpoint ?? 0) !== endpointIndex)
                continue;
            if (query.method !== method)
                continue;
            if (query.matchArgs) {
                if (query.matchArgs.length !== args.length)
                    continue;
                if (!query.matchArgs.every((arg, i) => arg === args[i])) {
                    continue;
                }
            }
            return pick(query, ["result", "persistValues", "extendMetadata"]);
        }
    }
}
const basicReportMappings = [
    false,
    "auto",
    "Binary Sensor",
];
function isBasicReportMapping(v) {
    return basicReportMappings.includes(v);
}
const basicSetMappings = [
    "event",
    "report",
    "auto",
    "Binary Sensor",
];
function isBasicSetMapping(v) {
    return basicSetMappings.includes(v);
}
//# sourceMappingURL=CompatConfig.js.map