import { EventEmitter } from 'node:events';
import hapNodeJs from '@homebridge/hap-nodejs';
import semver from 'semver';
import { Logger } from './logger.js';
import { PlatformAccessory } from './platformAccessory.js';
import { PluginManager } from './pluginManager.js';
import { User } from './user.js';
import getVersion from './version.js';
const log = Logger.internal;
// eslint-disable-next-line no-restricted-syntax
export var PluginType;
(function (PluginType) {
    PluginType["ACCESSORY"] = "accessory";
    PluginType["PLATFORM"] = "platform";
})(PluginType || (PluginType = {}));
// eslint-disable-next-line no-restricted-syntax
export var APIEvent;
(function (APIEvent) {
    /**
     * Event is fired once homebridge has finished with booting up and initializing all components and plugins.
     * When this event is fired it is possible that the Bridge accessory isn't published yet, if homebridge still needs
     * to wait for some {@see StaticPlatformPlugin | StaticPlatformPlugins} to finish accessory creation.
     */
    APIEvent["DID_FINISH_LAUNCHING"] = "didFinishLaunching";
    /**
     * This event is fired when homebridge gets shutdown. This could be a regular shutdown or an unexpected crash.
     * At this stage all Accessories are already unpublished and all PlatformAccessories are already saved to disk!
     */
    APIEvent["SHUTDOWN"] = "shutdown";
})(APIEvent || (APIEvent = {}));
// eslint-disable-next-line no-restricted-syntax
export var InternalAPIEvent;
(function (InternalAPIEvent) {
    InternalAPIEvent["REGISTER_ACCESSORY"] = "registerAccessory";
    InternalAPIEvent["REGISTER_PLATFORM"] = "registerPlatform";
    InternalAPIEvent["PUBLISH_EXTERNAL_ACCESSORIES"] = "publishExternalAccessories";
    InternalAPIEvent["REGISTER_PLATFORM_ACCESSORIES"] = "registerPlatformAccessories";
    InternalAPIEvent["UPDATE_PLATFORM_ACCESSORIES"] = "updatePlatformAccessories";
    InternalAPIEvent["UNREGISTER_PLATFORM_ACCESSORIES"] = "unregisterPlatformAccessories";
    // Matter events (matching HAP pattern)
    InternalAPIEvent["PUBLISH_EXTERNAL_MATTER_ACCESSORIES"] = "publishExternalMatterAccessories";
    InternalAPIEvent["REGISTER_MATTER_PLATFORM_ACCESSORIES"] = "registerMatterPlatformAccessories";
    InternalAPIEvent["UPDATE_MATTER_PLATFORM_ACCESSORIES"] = "updateMatterPlatformAccessories";
    InternalAPIEvent["UNREGISTER_MATTER_PLATFORM_ACCESSORIES"] = "unregisterMatterPlatformAccessories";
    InternalAPIEvent["UNREGISTER_EXTERNAL_MATTER_ACCESSORIES"] = "unregisterExternalMatterAccessories";
    InternalAPIEvent["UPDATE_MATTER_ACCESSORY_STATE"] = "updateMatterAccessoryState";
})(InternalAPIEvent || (InternalAPIEvent = {}));
// eslint-disable-next-line ts/no-unsafe-declaration-merging
export class HomebridgeAPI extends EventEmitter {
    version = 2.7; // homebridge API version
    serverVersion = getVersion(); // homebridge node module version
    // ------------------ LEGACY EXPORTS FOR PRE TYPESCRIPT  ------------------
    user = User;
    hap = hapNodeJs;
    hapLegacyTypes = hapNodeJs.LegacyTypes; // used for older accessories/platforms
    platformAccessory = PlatformAccessory;
    // ------------------------------------------------------------------------
    /**
     * Internal state tracking whether Matter is enabled for this bridge
     */
    matterEnabled = false;
    /**
     * Internal reference to MatterServer for API methods that need return values
     * @internal
     */
    _matterServer = null;
    /**
     * Internal reference to MatterBridgeManager for checking external servers
     * @internal
     */
    _matterManager = null;
    /**
     * Pending external accessory registrations
     * Map of registration ID to resolve function
     * @internal
     */
    _pendingExternalRegistrations = new Map();
    /**
     * Lazy-loaded Matter API implementation
     */
    _matterAPI;
    /**
     * Matter Protocol API (lazy-loaded).
     *
     * Returns the loaded MatterAPI instance, or `undefined` when Matter is not
     * configured for this bridge. Server / ChildBridgeFork call
     * {@link loadMatterAPI} before plugins run on Matter-enabled bridges, so
     * plugins observe a defined value here whenever {@link isMatterEnabled}
     * returns true.
     */
    get matter() {
        return this._matterAPI;
    }
    /**
     * In-flight loadMatterAPI promise. Cached so concurrent callers share a
     * single dynamic-import + construction; otherwise both could observe
     * `!this._matterAPI`, both await the import, and the second call's
     * MatterAPIImpl would clobber the first (along with anything wired into
     * `_pendingExternalRegistrations`).
     */
    _matterAPILoadPromise;
    /**
     * Load Matter API implementation. Idempotent.
     *
     * Called by Server / ChildBridgeFork during startup when Matter is
     * configured for the bridge, before plugin initialization. Plugins should
     * not call this directly — use {@link matter} instead.
     *
     * @internal
     */
    async loadMatterAPI() {
        if (this._matterAPI) {
            return;
        }
        if (!this._matterAPILoadPromise) {
            this._matterAPILoadPromise = (async () => {
                const { MatterAPIImpl } = await import('./matter/MatterAPIImpl.js');
                this._matterAPI = new MatterAPIImpl(this);
                // Mark Matter as enabled here, before plugins initialise. The later
                // `_setMatterEnabled(true)` calls inside MatterBridgeManager /
                // ChildBridgeMatterManager remain (idempotent) for code paths that
                // construct those managers directly without going through
                // loadMatterAPI. The contract `api.matter defined ⇔
                // api.isMatterEnabled()` now holds for plugins reading either from
                // their initialiser.
                this.matterEnabled = true;
            })();
        }
        return this._matterAPILoadPromise;
    }
    constructor() {
        super();
    }
    /**
     * Internal method to set Matter enabled status
     * Called by Server or ChildBridgeFork after Matter initialization
     * @internal
     */
    _setMatterEnabled(enabled) {
        this.matterEnabled = enabled;
    }
    /**
     * Internal method to set MatterServer reference
     * Called by Server or ChildBridgeFork after creating MatterServer
     * @internal
     */
    _setMatterServer(server) {
        this._matterServer = server;
    }
    /**
     * Internal method to set MatterBridgeManager reference
     * Called by Server or ChildBridgeFork to allow API access to external servers
     * @internal
     */
    _setMatterManager(manager) {
        this._matterManager = manager;
    }
    /**
     * Internal method to resolve pending external accessory registrations
     * Called by MatterBridgeManager when external accessories finish publishing
     * @internal
     */
    _resolveExternalRegistration(registrationId) {
        const resolve = this._pendingExternalRegistrations.get(registrationId);
        if (resolve) {
            resolve();
            this._pendingExternalRegistrations.delete(registrationId);
        }
    }
    versionGreaterOrEqual(version) {
        return semver.gte(this.serverVersion, version);
    }
    static isDynamicPlatformPlugin(platformPlugin) {
        return 'configureAccessory' in platformPlugin;
    }
    static isStaticPlatformPlugin(platformPlugin) {
        return 'accessories' in platformPlugin;
    }
    signalFinished() {
        this.emit("didFinishLaunching" /* APIEvent.DID_FINISH_LAUNCHING */);
    }
    signalShutdown() {
        this.emit("shutdown" /* APIEvent.SHUTDOWN */);
    }
    registerAccessory(pluginIdentifier, accessoryName, constructor) {
        if (typeof accessoryName === 'function') {
            constructor = accessoryName;
            accessoryName = pluginIdentifier;
            this.emit("registerAccessory" /* InternalAPIEvent.REGISTER_ACCESSORY */, accessoryName, constructor);
        }
        else {
            this.emit("registerAccessory" /* InternalAPIEvent.REGISTER_ACCESSORY */, accessoryName, constructor, pluginIdentifier);
        }
    }
    registerPlatform(pluginIdentifier, platformName, constructor) {
        if (typeof platformName === 'function') {
            constructor = platformName;
            platformName = pluginIdentifier;
            this.emit("registerPlatform" /* InternalAPIEvent.REGISTER_PLATFORM */, platformName, constructor);
        }
        else {
            this.emit("registerPlatform" /* InternalAPIEvent.REGISTER_PLATFORM */, platformName, constructor, pluginIdentifier);
        }
    }
    publishExternalAccessories(pluginIdentifier, accessories) {
        if (!PluginManager.isQualifiedPluginIdentifier(pluginIdentifier)) {
            log.info(`One of your plugins incorrectly registered an external accessory using the platform name (${pluginIdentifier}) and not the plugin identifier. Please report this to the developer!`);
        }
        accessories.forEach((accessory) => {
            // noinspection SuspiciousTypeOfGuard
            if (!(accessory instanceof PlatformAccessory)) {
                throw new TypeError(`${pluginIdentifier} attempt to register an accessory that isn't PlatformAccessory!`);
            }
            accessory._associatedPlugin = pluginIdentifier;
        });
        this.emit("publishExternalAccessories" /* InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES */, accessories);
    }
    registerPlatformAccessories(pluginIdentifier, platformName, accessories) {
        accessories.forEach((accessory) => {
            // noinspection SuspiciousTypeOfGuard
            if (!(accessory instanceof PlatformAccessory)) {
                throw new TypeError(`${pluginIdentifier} - ${platformName} attempt to register an accessory that isn't PlatformAccessory!`);
            }
            accessory._associatedPlugin = pluginIdentifier;
            accessory._associatedPlatform = platformName;
        });
        this.emit("registerPlatformAccessories" /* InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES */, accessories);
    }
    updatePlatformAccessories(accessories) {
        this.emit("updatePlatformAccessories" /* InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES */, accessories);
    }
    unregisterPlatformAccessories(pluginIdentifier, platformName, accessories) {
        accessories.forEach((accessory) => {
            // noinspection SuspiciousTypeOfGuard
            if (!(accessory instanceof PlatformAccessory)) {
                throw new TypeError(`${pluginIdentifier} - ${platformName} attempt to unregister an accessory that isn't PlatformAccessory!`);
            }
        });
        this.emit("unregisterPlatformAccessories" /* InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES */, accessories);
    }
    /**
     * Check if Matter is available in this version of Homebridge
     * @returns true if Homebridge version satisfies >= 2.0.0-alpha.0
     */
    isMatterAvailable() {
        return semver.gte(this.serverVersion, '2.0.0-alpha.0');
    }
    /**
     * Check if Matter is enabled for this bridge
     * For main bridge: returns true if Matter is enabled in `bridge.matter` config
     * For child bridge: returns true if Matter is enabled in the `_bridge.matter` config
     * @returns true if Matter is enabled
     */
    isMatterEnabled() {
        return this.matterEnabled;
    }
}
//# sourceMappingURL=api.js.map