"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 OnOffServer_exports = {};
__export(OnOffServer_exports, {
  OnOffBaseServer: () => OnOffBaseServer,
  OnOffServer: () => OnOffServer
});
module.exports = __toCommonJS(OnOffServer_exports);
var import_general_diagnostics = require("#behaviors/general-diagnostics");
var import_scenes_management = require("#behaviors/scenes-management");
var import_aggregator = require("#endpoints/aggregator");
var import_ServerNode = require("#node/ServerNode.js");
var import_general = require("@matter/general");
var import_protocol = require("@matter/protocol");
var import_general_diagnostics2 = require("@matter/types/clusters/general-diagnostics");
var import_on_off = require("@matter/types/clusters/on-off");
var import_OnOffBehavior = require("./OnOffBehavior.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const OnOffLogicBase = import_OnOffBehavior.OnOffBehavior.with(import_on_off.OnOff.Feature.Lighting);
class OnOffBaseServer extends OnOffLogicBase {
  initialize() {
    if (this.features.lighting && this.#getBootReason() !== import_general_diagnostics2.GeneralDiagnostics.BootReason.SoftwareUpdateCompleted && !this.endpoint.ownerOfType(import_aggregator.AggregatorEndpoint)) {
      const startUpOnOffValue = this.state.startUpOnOff ?? null;
      if (startUpOnOffValue !== null) {
        const currentOnOffStatus = this.state.onOff;
        const targetOnOffValue = startUpOnOffValue === import_on_off.OnOff.StartUpOnOff.Toggle ? !currentOnOffStatus : startUpOnOffValue === import_on_off.OnOff.StartUpOnOff.On;
        if (targetOnOffValue !== currentOnOffStatus) {
          this.state.onOff = targetOnOffValue;
        }
      }
    }
    if (this.features.lighting) {
      this.reactTo(this.events.onTime$Changed, this.#stopHeldTimer);
      this.reactTo(this.events.offWaitTime$Changed, this.#stopHeldTimer);
    }
    if (this.agent.has(import_scenes_management.ScenesManagementServer)) {
      this.agent.get(import_scenes_management.ScenesManagementServer).implementScenes(this, this.#applySceneValues);
      this.reactTo(this.events.onOff$Changed, this.#clearDelayedSceneApplyData);
    }
  }
  /**
   * Stop the active countdown timer when a write parks its attribute at a value that ends the countdown: 0 (the
   * decrement loop only runs while the value is > 0) or 0xFFFF (hold indefinitely). A running countdown picks up
   * any other written value on its next tick. Writes never start a countdown — only OnWithTimedOff does.
   */
  #stopHeldTimer() {
    if (this.state.onOff) {
      if (this.internal.timedOnTimer?.isRunning && (this.state.onTime === 0 || this.state.onTime === 65535)) {
        this.internal.timedOnTimer.stop();
      }
    } else if (this.internal.delayedOffTimer?.isRunning && (this.state.offWaitTime === 0 || this.state.offWaitTime === 65535)) {
      this.internal.delayedOffTimer.stop();
    }
  }
  get delayedPromises() {
    return this.internal.delayedPromises ??= new import_general.BasicMultiplex();
  }
  async [Symbol.asyncDispose]() {
    this.internal.timedOnTimer?.stop();
    this.internal.delayedOffTimer?.stop();
    await this.internal.delayedPromises?.close();
    await super[Symbol.asyncDispose]?.();
  }
  on() {
    if (!this.state.onOff) {
      this.#invalidateScenes();
    }
    this.state.onOff = true;
    if (this.features.lighting) {
      this.state.globalSceneControl = true;
      if ((this.state.onTime ?? 0) === 0) {
        if (this.delayedOffTimer.isRunning) {
          this.delayedOffTimer.stop();
        }
        this.state.offWaitTime = 0;
      }
    }
  }
  /** Invalidate all stored scenes manually for this endpoint in the Scenesmanagement cluster because SDK behavior. */
  #invalidateScenes() {
    this.agent.maybeGet(import_scenes_management.ScenesManagementServer)?.makeAllFabricSceneInfoEntriesInvalid();
  }
  off() {
    if (this.state.onOff) {
      this.#invalidateScenes();
    }
    this.state.onOff = false;
    if (this.features.lighting) {
      if (this.timedOnTimer.isRunning) {
        this.timedOnTimer.stop();
      }
      this.state.onTime = 0;
      if ((this.state.offWaitTime ?? 0) > 0 && this.state.offWaitTime !== 65535 && !this.delayedOffTimer.isRunning) {
        this.delayedOffTimer.start();
      }
    }
  }
  /**
   * Default implementation notes:
   * This method uses the on/off methods when timed actions should occur. This means that it is enough to override
   * on() and off() with custom control logic.
   */
  toggle() {
    if (this.state.onOff) {
      return this.off();
    } else {
      return this.on();
    }
  }
  /**
   * Default implementation notes:
   * * This implementation ignores the effect and just calls off().
   */
  offWithEffect() {
    if (this.state.globalSceneControl) {
      if ((0, import_protocol.hasRemoteActor)(this.context) && this.context.session.fabric !== void 0) {
        this.endpoint.agentFor(this.context).maybeGet(import_scenes_management.ScenesManagementServer)?.storeGlobalScene(this.context.session.fabric.fabricIndex);
      }
      this.state.globalSceneControl = false;
    }
    return this.off();
  }
  async onWithRecallGlobalScene() {
    if (this.state.globalSceneControl) {
      return;
    }
    if ((0, import_protocol.hasRemoteActor)(this.context) && this.context.session.fabric !== void 0 && this.agent.has(import_scenes_management.ScenesManagementServer)) {
      await this.endpoint.agentFor(this.context).maybeGet(import_scenes_management.ScenesManagementServer)?.recallGlobalScene(this.context.session.fabric.fabricIndex);
    }
    this.state.globalSceneControl = true;
    if (this.state.onTime === 0) {
      this.state.offWaitTime = 0;
    }
    await this.on();
  }
  /**
   * Default implementation notes:
   * * This method uses the on/off methods when timed actions should occur. This means that it is enough to override
   * on() and off() with custom control logic.
   */
  onWithTimedOff({ onOffControl, offWaitTime, onTime }) {
    if (onOffControl.acceptOnlyWhenOn && !this.state.onOff) {
      return;
    }
    if ((this.state.offWaitTime ?? 0) > 0 && !this.state.onOff) {
      this.state.offWaitTime = Math.min(offWaitTime ?? 0, this.state.offWaitTime ?? 0);
      if (!this.delayedOffTimer.isRunning && (this.state.offWaitTime ?? 0) > 0 && this.state.offWaitTime !== 65535) {
        this.delayedOffTimer.start();
      }
      return;
    }
    this.state.onTime = Math.max(onTime ?? 0, this.state.onTime ?? 0);
    this.state.offWaitTime = offWaitTime;
    if (this.state.onTime !== 0 && this.state.onTime !== 65535) {
      this.timedOnTimer.start();
    } else if (this.timedOnTimer.isRunning) {
      this.timedOnTimer.stop();
    }
    return this.on();
  }
  get timedOnTimer() {
    let timer = this.internal.timedOnTimer;
    if (timer === void 0) {
      timer = this.internal.timedOnTimer = import_general.Time.getPeriodicTimer(
        "Timed on",
        (0, import_general.Millis)(100),
        this.callback(this.#timedOnTick, { lock: true })
      );
    }
    return timer;
  }
  async #timedOnTick() {
    if (this.state.onTime === 65535) {
      this.internal.timedOnTimer?.stop();
      return;
    }
    let time = (this.state.onTime ?? 0) - 1;
    if (time <= 0) {
      time = 0;
      this.internal.timedOnTimer?.stop();
      this.state.offWaitTime = 0;
      await this.off();
    }
    this.state.onTime = time;
  }
  get delayedOffTimer() {
    let timer = this.internal.delayedOffTimer;
    if (timer === void 0) {
      timer = this.internal.delayedOffTimer = import_general.Time.getPeriodicTimer(
        "Delayed off",
        (0, import_general.Millis)(100),
        this.callback(this.#delayedOffTick, { lock: true })
      );
    }
    return timer;
  }
  /** Apply Scene values when requested from ScenesManagement cluster */
  #applySceneValues(values, transitionTime) {
    this.#clearDelayedSceneApplyData();
    const onOff = values.onOff;
    if (typeof onOff !== "boolean" || this.state.onOff === onOff) {
      return;
    }
    if (transitionTime === 0) {
      if (onOff) {
        return this.on();
      }
      return this.off();
    }
    this.internal.applyScenePendingOnOff = onOff;
    this.internal.applySceneDelayTimer = import_general.Time.getTimer(
      "delayed scene apply",
      (0, import_general.Millis)(transitionTime),
      this.callback(this.#applyDelayedSceneOnOffValue)
    ).start();
  }
  #clearDelayedSceneApplyData() {
    if (this.internal.applySceneDelayTimer?.isRunning) {
      this.internal.applySceneDelayTimer.stop();
    }
    this.internal.applySceneDelayTimer = void 0;
    this.internal.applyScenePendingOnOff = void 0;
  }
  #applyDelayedSceneOnOffValue() {
    const onOff = this.internal.applyScenePendingOnOff;
    this.#clearDelayedSceneApplyData();
    if (onOff === void 0) {
      return;
    }
    if (onOff) {
      this.delayedPromises.add(this.on());
    } else {
      this.delayedPromises.add(this.off());
    }
  }
  #delayedOffTick() {
    if (this.state.offWaitTime === 65535) {
      this.internal.delayedOffTimer?.stop();
      return;
    }
    let time = (this.state.offWaitTime ?? 0) - 1;
    if (time <= 0) {
      time = 0;
      this.internal.delayedOffTimer?.stop();
    }
    this.state.offWaitTime = time;
  }
  #getBootReason() {
    const rootEndpoint = this.env.get(import_ServerNode.ServerNode);
    if (rootEndpoint.behaviors.has(import_general_diagnostics.GeneralDiagnosticsBehavior)) {
      return rootEndpoint.stateOf(import_general_diagnostics.GeneralDiagnosticsBehavior).bootReason;
    }
  }
}
((OnOffBaseServer2) => {
  class Internal {
    timedOnTimer;
    delayedOffTimer;
    applySceneDelayTimer;
    applyScenePendingOnOff;
    delayedPromises;
  }
  OnOffBaseServer2.Internal = Internal;
})(OnOffBaseServer || (OnOffBaseServer = {}));
class OnOffServer extends OnOffBaseServer.with() {
}
//# sourceMappingURL=OnOffServer.js.map
