(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined'
    ? factory(exports)
    : typeof define === 'function' && define.amd
      ? define(['exports'], factory)
      : ((global =
          typeof globalThis !== 'undefined' ? globalThis : global || self),
        factory((global.TinyBaseSynchronizerWsServerSimple = {})));
})(this, function (exports) {
  'use strict';

  const EMPTY_STRING = '';
  const UTF8 = 'utf8';
  const MESSAGE = 'message';
  const strMatch = (str, regex) => (str == null ? undefined : str.match(regex));

  const isUndefined = (thing) => thing == undefined;
  const ifNotUndefined = (value, then, otherwise) =>
    isUndefined(value)
      ? otherwise == null
        ? undefined
        : otherwise()
      : then(value);
  const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);

  const object = Object;
  const objFreeze = object.freeze;

  const collSize = (coll) => {
    var _a;
    return (_a = coll == null ? undefined : coll.size) != null ? _a : 0;
  };
  const collHas = (coll, keyOrValue) => {
    var _a;
    return (_a = coll == null ? undefined : coll.has(keyOrValue)) != null
      ? _a
      : false;
  };
  const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
  const collClear = (coll) => coll.clear();
  const collForEach = (coll, cb) =>
    coll == null ? undefined : coll.forEach(cb);
  const collDel = (coll, keyOrValue) =>
    coll == null ? undefined : coll.delete(keyOrValue);

  const mapNew = (entries) => new Map(entries);
  const mapGet = (map, key) => (map == null ? undefined : map.get(key));
  const mapForEach = (map, cb) =>
    collForEach(map, (value, key) => cb(key, value));
  const mapSet = (map, key, value) =>
    isUndefined(value)
      ? (collDel(map, key), map)
      : map == null
        ? undefined
        : map.set(key, value);
  const mapEnsure = (map, key, getDefaultValue, hadExistingValue) => {
    if (!collHas(map, key)) {
      mapSet(map, key, getDefaultValue());
    }
    return mapGet(map, key);
  };

  const MESSAGE_SEPARATOR = '\n';
  const ifPayloadValid = (payload, then) => {
    const splitAt = payload.indexOf(MESSAGE_SEPARATOR);
    if (splitAt !== -1) {
      then(slice(payload, 0, splitAt), slice(payload, splitAt + 1));
    }
  };
  const createRawPayload = (clientId, remainder) =>
    clientId + MESSAGE_SEPARATOR + remainder;

  var __async = (__this, __arguments, generator) => {
    return new Promise((resolve, reject) => {
      var fulfilled = (value) => {
        try {
          step(generator.next(value));
        } catch (e) {
          reject(e);
        }
      };
      var rejected = (value) => {
        try {
          step(generator.throw(value));
        } catch (e) {
          reject(e);
        }
      };
      var step = (x) =>
        x.done
          ? resolve(x.value)
          : Promise.resolve(x.value).then(fulfilled, rejected);
      step((generator = generator.apply(__this, __arguments)).next());
    });
  };
  const PATH_REGEX = /\/([^?]*)/;
  const createWsServerSimple = (webSocketServer) => {
    const clientsByPath = mapNew();
    webSocketServer.on('connection', (client, request) =>
      ifNotUndefined(strMatch(request.url, PATH_REGEX), ([, pathId]) =>
        ifNotUndefined(request.headers['sec-websocket-key'], (clientId) =>
          __async(undefined, null, function* () {
            const clients = mapEnsure(clientsByPath, pathId, mapNew);
            mapSet(clients, clientId, client);
            client.on(MESSAGE, (data) =>
              ifPayloadValid(data.toString(UTF8), (toClientId, remainder) => {
                var _a;
                const forwardedPayload = createRawPayload(clientId, remainder);
                if (toClientId === EMPTY_STRING) {
                  mapForEach(clients, (otherClientId, otherClient) =>
                    otherClientId !== clientId
                      ? otherClient.send(forwardedPayload)
                      : 0,
                  );
                } else {
                  (_a = mapGet(clients, toClientId)) == null
                    ? undefined
                    : _a.send(forwardedPayload);
                }
              }),
            );
            client.on('close', () => {
              collDel(clients, clientId);
              if (collIsEmpty(clients)) {
                collDel(clientsByPath, pathId);
              }
            });
          }),
        ),
      ),
    );
    const getWebSocketServer = () => webSocketServer;
    const destroy = () => {
      collClear(clientsByPath);
      webSocketServer.close();
    };
    const wsServerSimple = {
      getWebSocketServer,
      destroy,
    };
    return objFreeze(wsServerSimple);
  };

  exports.createWsServerSimple = createWsServerSimple;
});
