/**
 * WindowCovering Cluster Behavior
 *
 * Handles window covering commands for blinds, shades, and curtains
 */
import { WindowCoveringServer } from '@matter/main/behaviors/window-covering';
import { Status, StatusResponseError } from '@matter/main/types';
import { MatterStatus } from '../errors.js';
import { getRegistryManager } from './EndpointContext.js';
/**
 * Feature-rich variant of the public WindowCoveringServer.
 *
 * We extend the public `WindowCoveringServer` (not the internal
 * `WindowCoveringBaseServer`) per apollon77's guidance on homebridge#3905 — the
 * Base class exists so matter.js's default-implementation methods have a concrete
 * feature set to compile against, and consumers shouldn't depend on it. Instead,
 * we declare the superset of features our overrides need via `.with(...)`. At
 * endpoint-attachment time, matter.js still narrows the effective feature set to
 * whatever the device type declares, so an endpoint that declares only Lift won't
 * advertise Tilt commands.
 */
const FeatureRichWindowCoveringServer = WindowCoveringServer.with('Lift', 'Tilt', 'PositionAwareLift', 'PositionAwareTilt');
/**
 * WindowCovering state property names
 * These correspond to the Matter.js WindowCovering cluster attribute names
 */
const WindowCoveringStateProps = {
    targetPositionLiftPercent100ths: 'targetPositionLiftPercent100ths',
    currentPositionLiftPercent100ths: 'currentPositionLiftPercent100ths',
    targetPositionTiltPercent100ths: 'targetPositionTiltPercent100ths',
    currentPositionTiltPercent100ths: 'currentPositionTiltPercent100ths',
};
/**
 * Custom WindowCovering Server that calls plugin handlers.
 */
export class HomebridgeWindowCoveringServer extends FeatureRichWindowCoveringServer {
    /**
     * Get the registry for this behavior's endpoint
     */
    getRegistry() {
        return getRegistryManager(this.endpoint).getRegistry(this.endpoint.id);
    }
    /**
     * Sync window covering position state to cache
     * @param endpointId - The endpoint ID
     * @param targetProperty - Target position property name (e.g., 'targetPositionLiftPercent100ths')
     * @param currentProperty - Current position property name (e.g., 'currentPositionLiftPercent100ths')
     */
    syncPositionStateToCache(endpointId, targetProperty, currentProperty) {
        const registry = this.getRegistry();
        const currentState = this.state;
        const stateUpdate = {};
        if (currentState[targetProperty] !== undefined) {
            stateUpdate[targetProperty] = currentState[targetProperty];
        }
        if (currentState[currentProperty] !== undefined) {
            stateUpdate[currentProperty] = currentState[currentProperty];
        }
        registry.syncStateToCache(endpointId, 'windowCovering', stateUpdate);
    }
    async upOrOpen() {
        const endpointId = this.endpoint.id;
        const registry = this.getRegistry();
        try {
            // Execute user handler
            await registry.executeHandler(endpointId, 'windowCovering', 'upOrOpen');
            // Only reached if handler succeeded - update Matter state
            await super.upOrOpen();
            // Sync state to cache - window covering opening
            this.syncPositionStateToCache(endpointId, WindowCoveringStateProps.targetPositionLiftPercent100ths, WindowCoveringStateProps.currentPositionLiftPercent100ths);
        }
        catch (error) {
            // If user handler already threw a StatusResponseError, propagate it as-is
            // This sends a proper Matter protocol error response to the controller
            if (MatterStatus.isMatterProtocolError(error)) {
                throw error;
            }
            // For other errors, wrap in appropriate StatusResponseError
            // This prevents the endpoint from crashing and keeps the device online
            const message = error instanceof Error ? error.message : String(error);
            throw new StatusResponseError(`Failed to open window covering: ${message}`, Status.Failure);
        }
    }
    async downOrClose() {
        const endpointId = this.endpoint.id;
        const registry = this.getRegistry();
        try {
            // Execute user handler
            await registry.executeHandler(endpointId, 'windowCovering', 'downOrClose');
            // Only reached if handler succeeded - update Matter state
            await super.downOrClose();
            // Sync state to cache - window covering closing
            this.syncPositionStateToCache(endpointId, WindowCoveringStateProps.targetPositionLiftPercent100ths, WindowCoveringStateProps.currentPositionLiftPercent100ths);
        }
        catch (error) {
            // If user handler already threw a StatusResponseError, propagate it as-is
            // This sends a proper Matter protocol error response to the controller
            if (MatterStatus.isMatterProtocolError(error)) {
                throw error;
            }
            // For other errors, wrap in appropriate StatusResponseError
            // This prevents the endpoint from crashing and keeps the device online
            const message = error instanceof Error ? error.message : String(error);
            throw new StatusResponseError(`Failed to close window covering: ${message}`, Status.Failure);
        }
    }
    async stopMotion() {
        const endpointId = this.endpoint.id;
        const registry = this.getRegistry();
        try {
            // Execute user handler
            await registry.executeHandler(endpointId, 'windowCovering', 'stopMotion');
            // Only reached if handler succeeded - update Matter state
            await super.stopMotion();
            // Sync state to cache - window covering stopped
            this.syncPositionStateToCache(endpointId, WindowCoveringStateProps.targetPositionLiftPercent100ths, WindowCoveringStateProps.currentPositionLiftPercent100ths);
        }
        catch (error) {
            // If user handler already threw a StatusResponseError, propagate it as-is
            // This sends a proper Matter protocol error response to the controller
            if (MatterStatus.isMatterProtocolError(error)) {
                throw error;
            }
            // For other errors, wrap in appropriate StatusResponseError
            // This prevents the endpoint from crashing and keeps the device online
            const message = error instanceof Error ? error.message : String(error);
            throw new StatusResponseError(`Failed to stop window covering: ${message}`, Status.Failure);
        }
    }
    async goToLiftPercentage(request) {
        const endpointId = this.endpoint.id;
        const registry = this.getRegistry();
        try {
            // Execute user handler
            await registry.executeHandler(endpointId, 'windowCovering', 'goToLiftPercentage', request);
            // Only reached if handler succeeded - update Matter state
            await super.goToLiftPercentage(request);
            // Sync state to cache - window covering moving to target position
            this.syncPositionStateToCache(endpointId, WindowCoveringStateProps.targetPositionLiftPercent100ths, WindowCoveringStateProps.currentPositionLiftPercent100ths);
        }
        catch (error) {
            // If user handler already threw a StatusResponseError, propagate it as-is
            // This sends a proper Matter protocol error response to the controller
            if (MatterStatus.isMatterProtocolError(error)) {
                throw error;
            }
            // For other errors, wrap in appropriate StatusResponseError
            // This prevents the endpoint from crashing and keeps the device online
            const message = error instanceof Error ? error.message : String(error);
            throw new StatusResponseError(`Failed to set window covering position: ${message}`, Status.Failure);
        }
    }
    async goToTiltPercentage(request) {
        const endpointId = this.endpoint.id;
        const registry = this.getRegistry();
        try {
            // Execute user handler
            await registry.executeHandler(endpointId, 'windowCovering', 'goToTiltPercentage', request);
            // Only reached if handler succeeded - update Matter state
            await super.goToTiltPercentage(request);
            // Sync state to cache - window covering tilting to target angle
            this.syncPositionStateToCache(endpointId, WindowCoveringStateProps.targetPositionTiltPercent100ths, WindowCoveringStateProps.currentPositionTiltPercent100ths);
        }
        catch (error) {
            // If user handler already threw a StatusResponseError, propagate it as-is
            // This sends a proper Matter protocol error response to the controller
            if (MatterStatus.isMatterProtocolError(error)) {
                throw error;
            }
            // For other errors, wrap in appropriate StatusResponseError
            // This prevents the endpoint from crashing and keeps the device online
            const message = error instanceof Error ? error.message : String(error);
            throw new StatusResponseError(`Failed to set window covering tilt: ${message}`, Status.Failure);
        }
    }
}
//# sourceMappingURL=WindowCoveringBehavior.js.map