"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 IpServiceStatus_exports = {};
__export(IpServiceStatus_exports, {
  IpServiceStatus: () => IpServiceStatus
});
module.exports = __toCommonJS(IpServiceStatus_exports);
var import_Diagnostic = require("#log/Diagnostic.js");
var import_Logger = require("#log/Logger.js");
var import_ServerAddress = require("#net/ServerAddress.js");
var import_Time = require("#time/Time.js");
var import_Abort = require("#util/Abort.js");
var import_Error = require("#util/Error.js");
var import_Set = require("#util/Set.js");
var import_IpServiceResolution = require("./IpServiceResolution.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_Logger.Logger.get("IpServiceStatus");
class IpServiceStatus {
  #service;
  #isReachable = false;
  #connecting = new import_Set.BasicSet();
  #resolveAbort;
  #resolving;
  #connectionInitiatedAt;
  #lastReceiptAt;
  constructor(service) {
    this.#service = service;
  }
  async close() {
    this.#stopResolving();
    if (this.#resolving) {
      await this.#resolving;
    }
  }
  /**
   * Is the service actively connecting?
   *
   * This is true so long as a promise passed to {@link connecting} is unresolved.
   */
  get isConnecting() {
    return this.#connecting.size > 0;
  }
  /**
   * Is the service currently reachable?
   *
   * This value is writable.  If you set {@link isReachable} to false and {@link isConnecting} is true, the service
   * enters discovery mode and begins active solicitation so long as neither condition changes.
   *
   * The service sets {@link isReachable} to true automatically if:
   *
   * - It discovers a new (previously unknown) address, or
   *
   * - The input promise to {@link connecting} resolves to true
   *
   * The service sets {@link isReachable} to false automatically if the input promise to {@link connecting} resolves
   * to false.
   */
  get isReachable() {
    return this.#isReachable;
  }
  /**
   * Are we actively performing MDNS discovery for the service?
   */
  get isResolving() {
    return this.#resolving !== void 0;
  }
  set isReachable(isReachable) {
    if (this.#isReachable === isReachable) {
      return;
    }
    this.#isReachable = isReachable;
    if (isReachable) {
      this.#maybeStopResolving();
    } else {
      this.#maybeStartResolving();
    }
  }
  get lastReceiptAt() {
    return this.#lastReceiptAt;
  }
  set lastReceiptAt(time) {
    this.#lastReceiptAt = time;
  }
  get connectionInitiatedAt() {
    return this.#connectionInitiatedAt;
  }
  /**
   * Register a new connection attempt.
   *
   * If {@link result} resolves as true the service is marked as reachable.  If {@link result} resolves as false
   * the service is marked as unreachable so subsequent attempts trigger MDNS resolution.
   *
   * If {@link result} rejects, the service is marked as unreachable and the error is logged.
   *
   * {@link isConnecting} will be true until {@link result} settles (resolves or rejects).
   */
  connecting(result) {
    logger.debug(this.#service.via, "Connecting");
    result.then(
      (returned) => {
        this.#connecting.delete(result);
        if (!this.#connecting.size) {
          this.#connectionInitiatedAt = void 0;
        }
        if (returned) {
          this.isReachable = true;
          logger.info(this.#service.via, "Connected");
        } else {
          this.isReachable = false;
          logger.debug(this.#service.via, "Connect attempt ended without session");
        }
      },
      (error) => {
        this.#connecting.delete(result);
        if (!this.#connecting.size) {
          this.#connectionInitiatedAt = void 0;
        }
        logger.error(this.#service.via, "Connection error:", (0, import_Error.asError)(error));
        this.isReachable = false;
      }
    );
    this.#connectionInitiatedAt = import_Time.Time.nowMs;
    this.#connecting.add(result);
    this.#maybeStartResolving();
  }
  #maybeStartResolving() {
    if (this.#isReachable || !this.isConnecting || this.#resolveAbort) {
      return;
    }
    const numAddresses = this.#service.addresses.size;
    let why;
    switch (numAddresses) {
      case 0:
        why = "no address known";
        break;
      case 1:
        why = "address is unreachable";
        break;
      default:
        why = `some of the ${numAddresses} known addresses are unreachable`;
    }
    logger.info(this.#service.via, "Resolving", import_Diagnostic.Diagnostic.weak(`(${why})`));
    this.#resolveAbort = new import_Abort.Abort();
    this.#resolving = (0, import_IpServiceResolution.IpServiceResolution)(this.#service, this.#resolveAbort).finally(() => {
      if (this.#resolveAbort?.aborted === false) {
        const addresses = [...this.#service.addresses].map(import_ServerAddress.ServerAddress.urlFor);
        logger.debug(this.#service.via, `Resolved as ${addresses.join(", ")}`);
      }
      this.#resolveAbort?.close();
      this.#resolveAbort = void 0;
      this.#resolving = void 0;
    });
  }
  #maybeStopResolving() {
    if (!this.#isReachable || this.isConnecting || !this.#resolveAbort) {
      return;
    }
    this.#stopResolving();
  }
  #stopResolving() {
    if (!this.#resolveAbort) {
      return;
    }
    this.#resolveAbort();
    logger.debug(this.#service.via, "Stopped resolving");
  }
}
//# sourceMappingURL=IpServiceStatus.js.map
