/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { asError, Diagnostic, InternalError, Logger } from "#general";
import { Node } from "#node/Node.js";
import { Mark } from "#protocol";
import { StatusResponse, StatusResponseError } from "#types";
import { ApiPath } from "./ApiPath.js";
import { RemoteResponse } from "./RemoteResponse.js";
import { EndpointResource } from "./resources/EndpointResource.js";
import { NodeResource } from "./resources/NodeResource.js";
import { ServerNodeResource } from "./resources/ServerNodeResource.js";
const loggers = /* @__PURE__ */ new Map();
var Api;
((Api2) => {
  async function resourceFor(agent, path) {
    let item;
    if ("peers" in agent.endpoint) {
      item = new ServerNodeResource(agent, void 0);
    } else if (agent.endpoint instanceof Node) {
      item = new NodeResource(agent, void 0);
    } else {
      item = new EndpointResource(agent, void 0);
    }
    const breadcrumb = [item];
    for (const segment of path) {
      const parent = breadcrumb[breadcrumb.length - 1];
      const item2 = await parent.childFor(segment);
      if (!item2) {
        return;
      }
      breadcrumb.push(item2);
    }
    return breadcrumb[breadcrumb.length - 1];
  }
  Api2.resourceFor = resourceFor;
  function log(level, facility, id, ...message) {
    let logger = loggers.get(facility);
    if (!logger) {
      loggers.set(facility, logger = Logger.get(facility));
    }
    logger[level](Diagnostic.via(id || "(anon)"), message);
  }
  Api2.log = log;
  function logRequest(facility, id, method, target) {
    log("info", facility, id, Mark.INBOUND, Diagnostic.strong(method), target);
  }
  Api2.logRequest = logRequest;
  function logResponse(facility, response) {
    const message = Array(Mark.OUTBOUND, RemoteResponse.describe(response));
    let level;
    switch (response.kind) {
      case "error":
        message.push(Diagnostic.errorMessage({ id: response.code, message: response.message }));
        level = "error";
        break;
      default:
        level = "info";
        break;
    }
    log(level, facility, response.id, message);
  }
  Api2.logResponse = logResponse;
  async function execute(facility, node, request, signal) {
    const { target, method, id } = request;
    logRequest(facility, id, method, target);
    try {
      const message = await node.act("remote", async (agent) => {
        const item = await resourceFor(agent, new ApiPath(target));
        if (item === void 0) {
          throw new StatusResponse.NotFoundError(`Target "${target}" not found`);
        }
        switch (method) {
          case "read":
            const value = item.read();
            if (value === void 0) {
              throw new StatusResponse.UnsupportedReadError(`Target "${target}" is not readable`);
            }
            value.convertToJson();
            return {
              kind: "value",
              id,
              // TODO - consider handling serialization here (in agent context) so copy is unnecessary
              value
            };
          case "write":
            item.write({ js: request.value });
            return { kind: "ok", id };
          case "add":
            item.add({ js: item.value });
            return { kind: "ok", id };
          case "delete":
            item.delete();
            return { kind: "ok", id };
          case "invoke": {
            const value2 = await item.invoke({ js: request.parameters });
            if (value2?.js === void 0 || value2?.js === null) {
              return { kind: "ok", id };
            }
            value2.convertToJson();
            return { id, kind: "value", value: value2 };
          }
          case "subscribe": {
            const options = { ...request };
            for (const field of ["target", "id", "method"]) {
              delete options[field];
            }
            const stream = item.subscribe(signal, {
              id,
              js: options
            });
            return { kind: "subscription", id, stream };
          }
        }
      });
      return message;
    } catch (error) {
      return errorResponseOf(facility, id, error);
    }
  }
  Api2.execute = execute;
  function errorResponseOf(facility, id, error) {
    error = asError(error);
    if (error instanceof StatusResponseError) {
      return { kind: "error", id, error };
    }
    log("error", facility, id, "Internal error:", error);
    return { kind: "error", id, error: new InternalError() };
  }
  Api2.errorResponseOf = errorResponseOf;
})(Api || (Api = {}));
export {
  Api
};
//# sourceMappingURL=Api.js.map
