'use strict';

var http = require('http');
var path = require('path');
var express = require('express');
var io = require('socket.io');
var uuid = require('uuid');
var spark_common = require('@microsoft/spark.common');
var spark_apps = require('@microsoft/spark.apps');
var routes = require('./routes');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

function _interopNamespace(e) {
  if (e && e.__esModule) return e;
  var n = Object.create(null);
  if (e) {
    Object.keys(e).forEach(function (k) {
      if (k !== 'default') {
        var d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () { return e[k]; }
        });
      }
    });
  }
  n.default = e;
  return Object.freeze(n);
}

var http__default = /*#__PURE__*/_interopDefault(http);
var path__default = /*#__PURE__*/_interopDefault(path);
var express__default = /*#__PURE__*/_interopDefault(express);
var io__default = /*#__PURE__*/_interopDefault(io);
var uuid__namespace = /*#__PURE__*/_interopNamespace(uuid);

class DevtoolsPlugin {
  name = "devtools";
  log;
  http;
  express;
  io;
  sockets = /* @__PURE__ */ new Map();
  httpPlugin = new spark_apps.HttpPlugin();
  events = new spark_common.EventEmitter();
  pending = {};
  constructor() {
    this.log = new spark_common.ConsoleLogger("@spark/app/devtools");
    this.express = express__default.default();
    this.http = http__default.default.createServer(this.express);
    this.io = new io__default.default.Server(this.http, { path: "/devtools/sockets" });
    this.io.on("connection", this.onConnection.bind(this));
    try {
      const dist = path__default.default.join(__dirname, "..", "devtools-web");
      this.express.use("/devtools", express__default.default.static(dist));
      this.express.get("/devtools/*", (_, res) => {
        res.sendFile(path__default.default.join(dist, "index.html"));
      });
    } catch (err) {
      this.log.warn(
        "failed to load devtools, please ensure you have installed `@microsoft/spark.devtools`"
      );
      this.log.warn(err);
    }
  }
  on(name, callback) {
    this.events.on(name, callback);
  }
  onInit(app) {
    app.event("activity.response", this.onActivityResponse.bind(this));
    app.event("activity.received", this.onActivityReceived.bind(this));
    app.event("activity.sent", this.onActivitySent.bind(this));
    const httpPlugin = app.getPlugin("http");
    if (httpPlugin && httpPlugin instanceof spark_apps.HttpPlugin) {
      this.httpPlugin = httpPlugin;
    }
    this.log = app.log.child("devtools");
  }
  /**
   * start listening
   * @param port port to listen on
   */
  async onStart(port = 3e3) {
    port += 1;
    this.express.use(
      routes.router({
        port,
        log: this.log,
        process: (token, activity) => {
          return new Promise((resolve, reject) => {
            this.pending[activity.id] = { resolve, reject };
            this.events.emit("activity.received", {
              token,
              activity
            });
          });
        }
      })
    );
    return await new Promise((resolve, reject) => {
      this.http.on("error", (err) => {
        reject(err);
      });
      this.http.listen(port, async () => {
        this.log.info(`available at http://localhost:${port}/devtools`);
        resolve();
      });
    });
  }
  async onSend(activity, ref) {
    const res = await this.httpPlugin.onSend(activity, ref);
    return res;
  }
  onStreamOpen(ref) {
    return new spark_apps.HttpStream((activity) => {
      return this.onSend(activity, ref);
    });
  }
  onActivityReceived({ activity }) {
    this.sendActivity({
      id: uuid__namespace.v4(),
      type: "activity.received",
      chat: activity.conversation,
      body: activity,
      sentAt: /* @__PURE__ */ new Date()
    });
  }
  onActivitySent({ activity, ref }) {
    this.sendActivity({
      id: uuid__namespace.v4(),
      type: "activity.sent",
      chat: ref.conversation,
      body: activity,
      sentAt: /* @__PURE__ */ new Date()
    });
  }
  onActivityResponse({ activity, response }) {
    const promise = this.pending[activity.id];
    if (!promise) return;
    promise.resolve(response);
    delete this.pending[activity.id];
  }
  onConnection(socket) {
    this.sockets.set(socket.id, socket);
    socket.on("disconnect", () => {
      this.sockets.delete(socket.id);
    });
  }
  send(event) {
    for (const socket of this.sockets.values()) {
      socket.emit(event.type, event);
    }
  }
  sendActivity(event) {
    for (const socket of this.sockets.values()) {
      socket.emit("activity", event);
      socket.emit(event.type, event);
    }
  }
}

exports.DevtoolsPlugin = DevtoolsPlugin;
//# sourceMappingURL=plugin.js.map
//# sourceMappingURL=plugin.js.map