import { __esDecorate, __runInitializers } from "tslib";
import * as __validateArgs from "./ManufacturerProprietaryCC._validateArgs.js";
const { validateArgs_ManufacturerProprietaryCCAPI_sendData, validateArgs_ManufacturerProprietaryCCAPI_sendAndReceiveData } = __validateArgs;
import { CommandClasses, ZWaveError, ZWaveErrorCodes, validatePayload, } from "@zwave-js/core";
import { Bytes } from "@zwave-js/shared";
import { CCAPI } from "../lib/API.js";
import { CommandClass, } from "../lib/CommandClass.js";
import { API, commandClass, expectedCCResponse, implementedVersion, } from "../lib/CommandClassDecorators.js";
import { ManufacturerSpecificCCValues } from "./ManufacturerSpecificCC.js";
import { getManufacturerId, getManufacturerProprietaryAPI, getManufacturerProprietaryCCConstructor, } from "./manufacturerProprietary/Decorators.js";
let ManufacturerProprietaryCCAPI = (() => {
    let _classDecorators = [API(CommandClasses["Manufacturer Proprietary"])];
    let _classDescriptor;
    let _classExtraInitializers = [];
    let _classThis;
    let _classSuper = CCAPI;
    let _instanceExtraInitializers = [];
    let _sendData_decorators;
    let _sendAndReceiveData_decorators;
    var ManufacturerProprietaryCCAPI = class extends _classSuper {
        static { _classThis = this; }
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _sendData_decorators = [validateArgs_ManufacturerProprietaryCCAPI_sendData()];
            _sendAndReceiveData_decorators = [validateArgs_ManufacturerProprietaryCCAPI_sendAndReceiveData()];
            __esDecorate(this, null, _sendData_decorators, { kind: "method", name: "sendData", static: false, private: false, access: { has: obj => "sendData" in obj, get: obj => obj.sendData }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _sendAndReceiveData_decorators, { kind: "method", name: "sendAndReceiveData", static: false, private: false, access: { has: obj => "sendAndReceiveData" in obj, get: obj => obj.sendAndReceiveData }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
            ManufacturerProprietaryCCAPI = _classThis = _classDescriptor.value;
            if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
            __runInitializers(_classThis, _classExtraInitializers);
        }
        constructor(host, endpoint) {
            super(host, endpoint);
            __runInitializers(this, _instanceExtraInitializers);
            // Read the manufacturer ID from Manufacturer Specific CC
            const manufacturerId = this.getValueDB().getValue(ManufacturerSpecificCCValues.manufacturerId.id);
            // If possible, try to defer to a specific subclass of this API
            if (manufacturerId != undefined) {
                const SpecificAPIConstructor = getManufacturerProprietaryAPI(manufacturerId);
                if (SpecificAPIConstructor != undefined
                    && new.target !== SpecificAPIConstructor) {
                    return new SpecificAPIConstructor(host, endpoint);
                }
            }
        }
        async sendData(manufacturerId, data) {
            const cc = new ManufacturerProprietaryCC({
                nodeId: this.endpoint.nodeId,
                endpointIndex: this.endpoint.index,
                manufacturerId,
            });
            cc.payload = data ? Bytes.view(data) : new Bytes();
            await this.host.sendCommand(cc, this.commandOptions);
        }
        async sendAndReceiveData(manufacturerId, data) {
            const cc = new ManufacturerProprietaryCC({
                nodeId: this.endpoint.nodeId,
                endpointIndex: this.endpoint.index,
                manufacturerId,
                unspecifiedExpectsResponse: true,
            });
            cc.payload = data ? Bytes.view(data) : new Bytes();
            const response = await this.host.sendCommand(cc, this.commandOptions);
            if (response) {
                return {
                    manufacturerId: response.manufacturerId,
                    data: response.payload,
                };
            }
        }
    };
    return ManufacturerProprietaryCCAPI = _classThis;
})();
export { ManufacturerProprietaryCCAPI };
function getReponseForManufacturerProprietary(ctx, cc) {
    return cc.unspecifiedExpectsResponse
        ? ManufacturerProprietaryCC
        : undefined;
}
function testResponseForManufacturerProprietaryRequest(sent, received) {
    // We expect a Manufacturer Proprietary response that has the same manufacturer ID as the request
    return sent.manufacturerId === received.manufacturerId;
}
let ManufacturerProprietaryCC = (() => {
    let _classDecorators = [commandClass(CommandClasses["Manufacturer Proprietary"]), implementedVersion(1), expectedCCResponse(getReponseForManufacturerProprietary, testResponseForManufacturerProprietaryRequest)];
    let _classDescriptor;
    let _classExtraInitializers = [];
    let _classThis;
    let _classSuper = CommandClass;
    var ManufacturerProprietaryCC = class extends _classSuper {
        static { _classThis = this; }
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
            ManufacturerProprietaryCC = _classThis = _classDescriptor.value;
            if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
            __runInitializers(_classThis, _classExtraInitializers);
        }
        constructor(options) {
            super(options);
            this.manufacturerId = options.manufacturerId
                ?? getManufacturerId(this);
            this.unspecifiedExpectsResponse = options.unspecifiedExpectsResponse;
            // To use this CC, a manufacturer ID must exist in the value DB
            // If it doesn't, the interview procedure will throw.
        }
        static from(raw, ctx) {
            validatePayload(raw.payload.length >= 1);
            const manufacturerId = raw.payload.readUInt16BE(0);
            // Try to parse the proprietary command
            const PCConstructor = getManufacturerProprietaryCCConstructor(manufacturerId);
            const payload = raw.payload.subarray(2);
            if (PCConstructor) {
                return PCConstructor.from(raw.withPayload(payload), ctx);
            }
            return new ManufacturerProprietaryCC({
                nodeId: ctx.sourceNodeId,
                manufacturerId,
                payload,
            });
        }
        manufacturerId;
        /**
         * @internal
         * This is used to indicate that an unspecified Manufacturer Proprietary CC instance expects a response.
         * Subclasses should roll their own `@expectedCCResponse` instead.
         */
        unspecifiedExpectsResponse;
        getManufacturerIdOrThrow() {
            if (this.manufacturerId == undefined) {
                throw new ZWaveError(`To use an instance of ManufacturerProprietaryCC, the manufacturer ID must be stored in the value DB`, ZWaveErrorCodes.ManufacturerProprietaryCC_NoManufacturerId);
            }
            return this.manufacturerId;
        }
        serialize(ctx) {
            const manufacturerId = this.getManufacturerIdOrThrow();
            // ManufacturerProprietaryCC has no CC command, so the first byte
            // is stored in ccCommand
            this.ccCommand = (manufacturerId >>> 8) & 0xff;
            // The 2nd byte is in the payload
            this.payload = Bytes.concat([
                [
                    // 2nd byte of manufacturerId
                    manufacturerId & 0xff,
                ],
                this.payload,
            ]);
            return super.serialize(ctx);
        }
        createSpecificInstance() {
            // Try to defer to the correct subclass
            if (this.manufacturerId != undefined) {
                const PCConstructor = getManufacturerProprietaryCCConstructor(this.manufacturerId);
                if (PCConstructor) {
                    return new PCConstructor({
                        nodeId: this.nodeId,
                        endpoint: this.endpointIndex,
                    });
                }
            }
        }
        async interview(ctx) {
            const node = this.getNode(ctx);
            // Read the manufacturer ID from Manufacturer Specific CC
            this.manufacturerId = this.getValue(ctx, ManufacturerSpecificCCValues.manufacturerId);
            const pcInstance = this.createSpecificInstance();
            if (pcInstance) {
                await pcInstance.interview(ctx);
            }
            else {
                ctx.logNode(node.id, {
                    message: `${this.constructor.name}: skipping interview refresh because the matching proprietary CC is not implemented...`,
                    direction: "none",
                });
            }
            // Remember that the interview is complete
            this.setInterviewComplete(ctx, true);
        }
        async refreshValues(ctx, options) {
            const node = this.getNode(ctx);
            if (this.manufacturerId == undefined) {
                // Read the manufacturer ID from Manufacturer Specific CC
                this.manufacturerId = this.getValue(ctx, ManufacturerSpecificCCValues.manufacturerId);
            }
            const pcInstance = this.createSpecificInstance();
            if (pcInstance) {
                await pcInstance.refreshValues(ctx, options);
            }
            else {
                ctx.logNode(node.id, {
                    message: `${this.constructor.name}: skipping value refresh because the matching proprietary CC is not implemented...`,
                    direction: "none",
                });
            }
        }
    };
    return ManufacturerProprietaryCC = _classThis;
})();
export { ManufacturerProprietaryCC };
//# sourceMappingURL=ManufacturerProprietaryCC.js.map