"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const matter_server_1 = require("../modules/matter-server");
const ts_deferred_1 = require("ts-deferred");
const ObservableMap_1 = require("../utils/ObservableMap");
function default_1(RED) {
    function MatterServerNode(config) {
        const node = this;
        RED.nodes.createNode(node, config);
        const devices = new ObservableMap_1.ObservableMap();
        RED.nodes.eachNode((n) => {
            if (n.server === node.id &&
                n.devicecategory !== 'aggregated') {
                devices.set(n.id, false);
            }
        });
        const nodeRedFolderPath = RED.settings.userDir;
        const serverInit = new ts_deferred_1.Deferred();
        const serverStart = new ts_deferred_1.Deferred();
        node.serverPromise = serverStart.promise;
        const matterServer = new matter_server_1.MatterServer();
        matterServer
            .init({
            storageLocation: `${nodeRedFolderPath}/node-red-matter/matter-servers/${node.id}`,
        })
            .then(() => {
            serverInit.resolve();
        });
        async function startServer() {
            node.log('Starting matter server');
            await matterServer.start();
            node.log('Connecting all commissioning controllers');
            try {
                await matterServer.connectAllCommissioningControllers();
            }
            catch (e) {
                node.error(e);
            }
            node.log('Matter server started');
            serverStart.resolve(matterServer.matterServer);
        }
        if (devices.size === 0) {
            serverInit.promise.then(() => {
                startServer();
            });
        }
        const timeout = setTimeout(() => {
            node.warn('Not all devices were added to the server, starting anyway but in a potentially unstable state');
            startServer();
        }, 10000);
        devices.addListener(async (devices) => {
            // Only start the server after all the devices have been added or failed to be added
            if (Array.from(devices.values()).every((value) => value)) {
                clearTimeout(timeout);
                node.log(`All devices added (${devices.size}/${devices.size})`);
                startServer();
            }
            else {
                const addedDevices = Array.from(devices.values()).filter((value) => value === true).length;
                node.log(`Waiting for all devices to be added (${addedDevices}/${devices.size}))`);
            }
        });
        node.addListener('add_commissioning_server', async (nodeId, commissioningServer) => {
            await serverInit.promise;
            try {
                matterServer.addCommissioningServer(commissioningServer);
                node.log(`Added commissioning server for ${nodeId}`);
            }
            catch (e) {
                node.error(e);
            }
            devices.set(nodeId, true);
        });
        node.addListener('add_commissioning_controller', async (nodeId, commissioningController) => {
            await serverInit.promise;
            node.log(`Added commissioning controller for ${nodeId}`);
            try {
                matterServer.addCommissioningController(commissioningController);
            }
            catch (e) {
                node.error(e);
            }
            devices.set(nodeId, true);
        });
        node.on('close', async (destroyed, done) => {
            await serverInit.promise;
            if (destroyed === false) {
                node.log('Stopping matter server');
                await matterServer.stop();
            }
            else {
                node.log('Destroying matter server');
                await matterServer.destroy();
            }
            done();
        });
    }
    RED.nodes.registerType('matter-server', MatterServerNode);
}
exports.default = default_1;
