"use strict";
// import { injectable, inject, interfaces } from "inversify"
// import _ = require("lodash");
// import { Observable } from 'rxjs';
// import { concatMap, take, tap, } from 'rxjs/operators';
// import { Guid } from "guid-typescript";
// import * as stringify from "json-stringify-safe"
// import { INTERFACES, IBetterLogger } from "@codiac.io/codiac-common";
// import { RxWebsocketSubject } from './rx-websocket-subject'
// import { IMessage, SocketAction, SocketActionHandler } from './socket-contracts';
// /** Configuration for the relay web socket client
//  * (ie: duplex comms with the relay via Websocket)  */
// @injectable()
// export class RelaySocketListenerSettings {
//   constructor() { }
//   /** Fully qualified url of the target web socket service. */
//   public url?: string | undefined;
//   /** The pause in mmilliseconds to wait after a connection failure before attempting to reconnect.  */
//   public reconnectIntervalMs?: number | undefined;
//   /** The number of retries on a failed connection before throwing exception. */
//   public reconnectAttempts?: number | undefined;
// }
// /** Meta added to a message handler for facility in managing message subscribers. */
// class HandlerSubx {
//   constructor(public id: string, public handler: SocketActionHandler) {
//   }
// }
// /**
//  * **USAGE:**
//  *
//  * At bootstrap time...
//  * ```
//  * RelaySocketListenerService.bootstrap(ioc, { reconnectIntervalMs: 2000 });
//  * ```
//  * At ctor injection...
//  * ```
//  * export class MyClass {
//  *  constructor(@inject(RelaySocketListener) private socket: RelaySocketListener) { ... }
//  *
//  *  public doSomething() {
//  *    // wire up a msg handler...
//  *    this.socket.listenFor("MyAction", msg => {
//  *      console.log(`I just got a ${msg.action}, with cid: ${msg.correlationId}`);
//  *    });
//  *
//  *    // Start listening (if its not already)
//  *    this.socket.start();
//  *  }
//  * }
//  * ```
//  */
// @injectable()
// export class RelaySocketListener {
//   public static bootstrap(ioc: interfaces.Container, settings?: RelaySocketListenerSettings | undefined): void {
//     ioc.bind(RelaySocketListenerSettings).toConstantValue(settings ?? {});
//     ioc.bind(RelaySocketListener).toSelf().inSingletonScope();  // <-- There can be only one socket connection from the CLI.
//   }
//   public static readonly DEFAULT_SETTINGS: Required<RelaySocketListenerSettings> = {
//     url: "ws://localhost:5798",
//     reconnectIntervalMs: 2000,
//     /** Deliberately kept short because the retry is limited to a single cli command execution,
//      * not an ongoing user session (thus it needs to fail fast).  */
//     reconnectAttempts: 5
//   };
//   constructor(
//     @inject(RelaySocketListenerSettings) settings: RelaySocketListenerSettings,
//     @inject(INTERFACES.IBetterLogger) private logger: IBetterLogger
//   ) {
//     this.settings = _.assignIn({}, RelaySocketListener.DEFAULT_SETTINGS, settings);
//     this.subscribers = {};
//   }
//   private readonly settings: Required<RelaySocketListenerSettings>;
//   private rxWebsocketSubject: RxWebsocketSubject<IMessage> | undefined
//   /** Connects and initiates the listeners.
//    * Returns the SocketId.
//    * (IDEMPOTENT) Lazy-start: this method wont duplicate connections if it's already connected to the remote websocket server.
//    */
//   public async start(): Promise<string> {
//     return new Promise<string>(async (resolve, reject) => {
//       // if (this.rxWebsocketSubject?.connectionStatus !== connected) {
//       if (this.rxWebsocketSubject == undefined) {
//         this.rxWebsocketSubject = new RxWebsocketSubject(this.settings.url, this.settings.reconnectIntervalMs, this.settings.reconnectAttempts, this.routeInboundMessage, this.logger)
//       }
//       this.rxWebsocketSubject.onSocketConnection((err, socketId) => {
//         if (err) {
//           reject(err);
//         } else {
//           resolve(socketId);
//         }
//       })
//       this.rxWebsocketSubject.connect();
//       this.rxWebsocketSubject.subscribe();
//       // }
//       // How do we observe the connection status and return the socketId once connected?
//       // resolve("fakeSocketId-123-345");
//     })
//   }
//   /** (IDEMPOTENT) Lazy-stop: this method can be called even if the (one-and-only) socket is already closed. */
//   public stop(): void {
//     if (this.rxWebsocketSubject) {
//       if (this.rxWebsocketSubject.closed !== true  /* .isStopped ? */) {
//         this.rxWebsocketSubject.complete();  // Is this right?
//       }
//     }
//   }
//   // public go(correlationId?: string): void {
//   //   if (correlationId) this.correlationId = correlationId;
//   //   const socketRequest: SocketAction = { action: this.ACTION, correlationId: correlationId, payload: { authorization: this.authTokenQuery.JWT } } // new HttpHeaders({ authorization: this.authTokenQuery.JWT })
//   //   this.rxWebsocketSubject.send(socketRequest);
//   // }
//   /** Late-bound subscribers to incoming messages, mapped by `SocketAction.action`.
//    *
//    * If multiple handlers are registered for a given action,
//    * they get fired in order they subscribed (first-come first served).
//    */
//   private subscribers: { [action: string]: HandlerSubx[] };
//   /** Returns the subscription id for the handler (reqd for unsubcribing).
//    */
//   public listenFor(action: string, handler: SocketActionHandler): string {
//     if (this.subscribers[action] == undefined) {
//       this.subscribers[action] = [];
//     }
//     let subx: HandlerSubx = {
//       id: Guid.create().toString(),
//       handler: handler
//     };
//     this.subscribers[action].push(subx);
//     return subx.id;
//   }
//   /** Removes the given listener.  (IDEMPOTENT) Returns whether a handler was indeed removed (false if it didn't exist).
//    *
//    * Throws any exceptions. */
//   public unlisten(action: string, subscriptionId: string): boolean {
//     let existings = this.subscribers[action];
//     if (existings && existings.length > 0) {
//       let removed = _.remove(existings, x => x.id === subscriptionId);
//       return Boolean(removed.length > 0);
//     } else {
//       return false;
//     }
//   }
//   /** Fires any registered handlers. */
//   private routeInboundMessage = (msg: MessageEvent | SocketAction) => {
//     if ((<any>msg).action) {
//       let actionMsg = <SocketAction>msg;
//       let subxs = this.subscribers[actionMsg.action];
//       if (subxs && subxs.length > 0) {
//         for (let subx of subxs) {
//           try {
//             this.logger.debug(`Handling inbound [${actionMsg.action}] SocketAction [handler id: ${subx.id}]...`);
//             /* TODO: await */ subx.handler(actionMsg);
//           } catch (err) {
//             this.logger.error(`Unhandled error in [${actionMsg.action}] SocketAction handler [id: ${subx.id}]: ${err.name ?? ""} ${err.message ?? "(No details available)"}`);
//           }
//         }
//       } else {
//         this.logger.warn(`Received unhandled [${actionMsg.action}] message from [${this.settings.url}];`);
//       }
//     } else {
//       this.logger.warn(`Received unrecognized WebSocket message.`, stringify(msg));
//     }
//     return msg;  // <--- Do we need to return this?
//   }
// }
//# sourceMappingURL=relay-socket-listener.js.map