"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var SwitchServer_exports = {};
__export(SwitchServer_exports, {
  SwitchBaseServer: () => SwitchBaseServer,
  SwitchServer: () => SwitchServer
});
module.exports = __toCommonJS(SwitchServer_exports);
var import_switch = require("#clusters/switch");
var import_general = require("#general");
var import_model = require("#model");
var import_types = require("#types");
var import_SwitchBehavior = require("./SwitchBehavior.js");
/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const DEFAULT_MULTIPRESS_DELAY = (0, import_general.Millis)(300);
const DEFAULT_LONG_PRESS_DELAY = (0, import_general.Seconds)(2);
const logger = import_general.Logger.get("SwitchServer");
const SwitchServerBase = import_SwitchBehavior.SwitchBehavior.for(import_switch.Switch.Complete).with(
  import_switch.Switch.Feature.LatchingSwitch,
  import_switch.Switch.Feature.MomentarySwitch,
  import_switch.Switch.Feature.MomentarySwitchRelease,
  import_switch.Switch.Feature.MomentarySwitchLongPress,
  import_switch.Switch.Feature.MomentarySwitchMultiPress,
  import_switch.Switch.Feature.ActionSwitch
);
const schema = SwitchServerBase.schema.extend({
  children: [
    (0, import_model.FieldElement)({
      name: "longPressDelay",
      type: "duration",
      conformance: "MSL",
      default: DEFAULT_LONG_PRESS_DELAY
    }),
    (0, import_model.FieldElement)({
      name: "multiPressDelay",
      type: "duration",
      conformance: "MSM",
      default: DEFAULT_MULTIPRESS_DELAY
    }),
    (0, import_model.FieldElement)({
      name: "momentaryNeutralPosition",
      type: "uint8",
      conformance: "[MS]",
      default: 0
    })
  ]
});
class SwitchBaseServer extends SwitchServerBase {
  static schema = schema;
  initialize() {
    this.state.rawPosition = this.state.currentPosition;
    this.internal.currentUnstablePosition = this.state.currentPosition;
    this.internal.previouslyReportedPosition = this.state.currentPosition;
    this.reactTo(this.events.rawPosition$Changing, this.#assertPositionInRange);
    this.reactTo(this.events.currentPosition$Changing, this.#assertPositionInRange);
    this.reactTo(this.events.rawPosition$Changed, this.#debounceRawPosition);
    this.reactTo(this.events.currentPosition$Changed, this.#handleSwitchPositionChange);
  }
  /** Method to reset the state of the Switch to start a clean new cycle. Mainly relevant for automated testing. */
  resetState() {
    const neutralPosition = this.state.momentaryNeutralPosition;
    this.internal.currentUnstablePosition = neutralPosition;
    this.internal.previouslyReportedPosition = neutralPosition;
    this.internal.multiPressReportingAborted = false;
    this.internal.currentNumberOfPressesCounter = 1;
    this.internal.previousMultiPressPosition = null;
    this.internal.currentLongPressPosition = null;
    this.internal.currentIsLongPress = false;
    this.internal.multiPressTimer?.stop();
    this.internal.longPressTimer?.stop();
    logger.info("State of Switch got reset");
  }
  // TODO remove when Validator logic can assess that with 1.3 introduction
  #assertPositionInRange(position) {
    if (position < 0 || position >= this.state.numberOfPositions) {
      throw new import_types.StatusResponseError(`Position ${position} invalid`, import_types.StatusCode.ConstraintError);
    }
  }
  #debounceRawPosition(newPosition) {
    if (this.state.debounceDelay) {
      this.internal.debounceTimer?.stop();
      this.internal.currentUnstablePosition = newPosition;
      this.internal.debounceTimer = import_general.Time.getTimer(
        "debounce",
        this.state.debounceDelay,
        this.callback(this.#setCurrentPositionAfterDebounce, { lock: true })
      ).start();
    } else {
      this.state.currentPosition = newPosition;
    }
  }
  #setCurrentPositionAfterDebounce() {
    this.state.currentPosition = this.internal.currentUnstablePosition;
  }
  #handleSwitchPositionChange(newPosition) {
    if (this.features.latchingSwitch) {
      this.events.switchLatched?.emit({ newPosition }, this.context);
      return;
    }
    let pressSequenceFinished = false;
    if (newPosition !== this.state.momentaryNeutralPosition && !this.internal.multiPressReportingAborted && (!this.features.actionSwitch || !this.internal.multiPressTimer?.isRunning)) {
      this.events.initialPress?.emit({ newPosition }, this.context);
    }
    if (this.features.momentarySwitchLongPress) {
      if (newPosition === this.state.momentaryNeutralPosition) {
        if (this.internal.longPressTimer?.isRunning) {
          if (!this.features.actionSwitch) {
            this.events.shortRelease?.emit(
              { previousPosition: this.internal.previouslyReportedPosition },
              this.context
            );
          }
        } else if (this.internal.currentIsLongPress) {
          this.events.longRelease?.emit(
            { previousPosition: this.internal.previouslyReportedPosition },
            this.context
          );
          this.internal.multiPressTimer?.stop();
          pressSequenceFinished = true;
        }
      }
      this.internal.longPressTimer?.stop();
      this.internal.currentIsLongPress = false;
      this.internal.currentLongPressPosition = null;
      if (newPosition !== this.state.momentaryNeutralPosition) {
        this.internal.currentLongPressPosition = newPosition;
        this.internal.longPressTimer = import_general.Time.getTimer(
          "longPress",
          this.state.longPressDelay,
          this.callback(this.#handleLongPress, { lock: true })
        ).start();
      }
    } else if (this.features.momentarySwitchRelease && newPosition === this.state.momentaryNeutralPosition) {
      this.events.shortRelease?.emit(
        { previousPosition: this.internal.previouslyReportedPosition },
        this.context
      );
    }
    if (this.features.momentarySwitchMultiPress) {
      if (this.internal.multiPressTimer?.isRunning && newPosition !== this.state.momentaryNeutralPosition && !this.internal.multiPressReportingAborted && !this.internal.currentIsLongPress && !pressSequenceFinished) {
        this.internal.currentNumberOfPressesCounter++;
        if (!this.features.actionSwitch) {
          this.events.multiPressOngoing?.emit(
            {
              newPosition,
              currentNumberOfPressesCounted: this.internal.currentNumberOfPressesCounter
            },
            this.context
          );
        }
        if (this.state.multiPressMax !== void 0 && this.internal.currentNumberOfPressesCounter > this.state.multiPressMax) {
          this.internal.multiPressReportingAborted = true;
          this.events.multiPressComplete?.emit(
            {
              previousPosition: newPosition,
              totalNumberOfPressesCounted: 0
            },
            this.context
          );
          pressSequenceFinished = true;
        }
      }
      this.internal.multiPressTimer?.stop();
      if (!pressSequenceFinished) {
        this.internal.multiPressTimer = import_general.Time.getTimer(
          "multiPress",
          this.state.multiPressDelay,
          this.callback(this.#handleMultiPressComplete, { lock: true })
        ).start();
      }
      if (this.internal.previouslyReportedPosition !== this.state.momentaryNeutralPosition) {
        this.internal.previousMultiPressPosition = this.internal.previouslyReportedPosition;
      }
    }
    this.internal.previouslyReportedPosition = newPosition;
  }
  // Method is called by a timer, so no change to the position for longPressDelay
  #handleLongPress() {
    if (this.internal.currentLongPressPosition === null || this.internal.currentNumberOfPressesCounter > 1) {
      return;
    }
    this.events.longPress?.emit({ newPosition: this.internal.currentLongPressPosition }, this.context);
    this.internal.currentIsLongPress = true;
    this.internal.multiPressTimer?.stop();
  }
  #handleMultiPressComplete() {
    if (this.internal.previousMultiPressPosition === null || this.internal.longPressTimer?.isRunning) {
      return;
    }
    if (!this.internal.multiPressReportingAborted) {
      this.events.multiPressComplete?.emit(
        {
          previousPosition: this.internal.previousMultiPressPosition,
          totalNumberOfPressesCounted: this.internal.currentNumberOfPressesCounter
        },
        this.context
      );
    }
    this.internal.currentNumberOfPressesCounter = 1;
    this.internal.multiPressReportingAborted = false;
    this.internal.previousMultiPressPosition = null;
  }
  async [Symbol.asyncDispose]() {
    this.internal.debounceTimer?.stop();
    this.internal.longPressTimer?.stop();
    this.internal.multiPressTimer?.stop();
    await super[Symbol.asyncDispose]?.();
  }
}
((SwitchBaseServer2) => {
  class Internal {
    /** Timer to debounce the raw position. */
    debounceTimer;
    /** Timer to detect a long press. */
    longPressTimer;
    /** Timer to detect multi presses. */
    multiPressTimer;
    /** Counter to count the number of presses. */
    currentNumberOfPressesCounter = 1;
    /** Indicator if the multi press sequence was aborted. */
    multiPressReportingAborted = false;
    /** Position previously reported in events. */
    previouslyReportedPosition = 0;
    /** Position of the previous multi press. */
    previousMultiPressPosition = null;
    /** Position of the current long press. */
    currentLongPressPosition = null;
    /** Flag to indicate if the current press is a long press. */
    currentIsLongPress = false;
    /** Position of the current unstable position which is debounced */
    currentUnstablePosition = 0;
  }
  SwitchBaseServer2.Internal = Internal;
  class State extends SwitchServerBase.State {
    /** Raw position of the switch. Set this to debounce the value. */
    rawPosition = 0;
    /**
     * Debounce Delay to wait until a newly reported raw position is considered stable and written to the
     * currentPosition attribute.
     */
    debounceDelay;
    /** Time to wait until a value is considered "long" pressed */
    longPressDelay = DEFAULT_LONG_PRESS_DELAY;
    /** Timeframe starting with a stable release to detect multi-presses. */
    multiPressDelay = DEFAULT_MULTIPRESS_DELAY;
    /** Number of the position considered as the neutral position for the momentary switch. */
    momentaryNeutralPosition = 0;
    // These are mandatory; provide reasonable defaults
    numberOfPositions = 2;
    multiPressMax = 2;
  }
  SwitchBaseServer2.State = State;
  class Events extends SwitchServerBase.Events {
    rawPosition$Changed = (0, import_general.Observable)();
    rawPosition$Changing = (0, import_general.Observable)();
  }
  SwitchBaseServer2.Events = Events;
})(SwitchBaseServer || (SwitchBaseServer = {}));
class SwitchServer extends SwitchBaseServer.for((0, import_types.ClusterType)(import_switch.Switch.Base)) {
}
//# sourceMappingURL=SwitchServer.js.map
