"use strict";
// COMMENTED OUT BC: Migrated to @codiac.io/codiac-messaging
// import { inject, injectable, interfaces } from "inversify";
// import * as _ from "lodash";
// import { Guid } from "guid-typescript";
// import * as nats from "nats";
// import * as YAML from "yaml";
// import { IBetterLogger, INTERFACES } from "@codiac.io/codiac-common";
// import { Result } from "@codiac.io/codiac-common/contracts";
// import { IMessageReceivedMeta, IMessageSendMeta, IMessagingClient, MessagePayload, MessagingDefaults } from "@codiac.io/codiac-messaging/dist/nats/client"; // "../../uilogic/i-messaging-client";
// import { ApiUserCreds } from "../codiac-api";
// @injectable()
// export class NatsClientSettings {
//   constructor(
//     public natsHost: string,
//     public natsPort: number,
//     public serializer: "json" | "yaml" | "string",
//     /** The amount of time to wait for a response to a given request.  */
//     public requestTimeoutInSecs: number
//   ) {
//   }
// }
// @injectable()
// export class NatsClient implements IMessagingClient {
//   public static bootstrap(ioc: interfaces.Container, settings?: Partial<NatsClientSettings>): void {
//     ioc.bind(NatsClientSettings).toConstantValue(settings as NatsClientSettings);
//     ioc.bind(NatsClient).toSelf();
//   }
//   public static defaults: NatsClientSettings = {
//     natsHost: "localhost",
//     natsPort: 4222,
//     serializer: "json",
//     requestTimeoutInSecs: 30
//   }
//   /** Applied to this.tokenHeaderParam in the ctor.
//    *  Typical name of the http request header that declares the authentication token for the request.  */
//   public static DEFAULT_TOKEN_HEADER_PARAM = "authorization";
//   constructor(
//     @inject(ApiUserCreds) private apiUserCreds: ApiUserCreds | undefined,
//     @inject(NatsClientSettings) settings: Partial<NatsClientSettings>,
//     @inject(INTERFACES.IBetterLogger) private logger: IBetterLogger,
//   ) {
//     this.settings = _.merge({}, NatsClient.defaults, settings ?? {});  // Overlays the provided settings over the defaults
//     this.natsUrl = "nats://".concat(this.settings.natsHost, ":", this.settings.natsPort.toString());
//   }
//   public settings: NatsClientSettings;
//   public natsUrl: string;
//   private cnxn: nats.NatsConnection | undefined;
//   private listeners: nats.Subscription[] = [];
//   public async connect(): Promise<string> {
//     try {
//       this.cnxn = await nats.connect({
//         servers: [this.natsUrl]
//       });
//       return this.connectionId!;
//     } catch (err) {
//       const errMsg = "Error connecting to ".concat("[", this.natsUrl, "]: ", err.message ?? "no details available");
//       this.logger.error(errMsg, err.stack);
//       throw new Error(errMsg);
//     }
//   }
//   public async disconnect(): Promise<void> {
//     try {
//       if (this.cnxn && (!this.cnxn.isClosed())) {
//         this.logger.detail(`Closing connection`);
//         await this.cnxn.drain();
//         await this.cnxn.close();
//       } else {
//         this.logger.detail(`Skipping disconnect: No connection is currently open.`);
//       }
//       return;
//     } catch (err) {
//       throw err;
//     }
//   }
//   public isConnected(): boolean {
//     return !(this.cnxn == undefined || this.cnxn.isClosed());
//   }
//   public get connectionId(): string | undefined {
//     return this.cnxn?.info?.client_id.toString();
//   }
//   /** TODO: Expose typesafe messages instead of raw nats.Msg */
//   public subscribe<TMsg extends MessagePayload>(topics: string, handler: (err: Error | null, msg: TMsg, meta: IMessageReceivedMeta, raw: nats.Msg) => Promise<void>): string {
//     // if (this.cnxn == undefined || this.cnxn.isClosed()) {
//     //   await this.connect();
//     // }
//     // if (this.cnxn == undefined) throw new Error(`Unable to subscribe: Failed connecting to nats server.`);
//     try {
//       if (!this.isConnected() || this.cnxn == undefined) {
//         throw new Error("Client is not connected to the nats server.");
//       }
//       let optz: nats.SubscriptionOptions = {
//         callback: async (errResponse, natsMsg) => {
//           try {
//             this.logger.debug("received message ".concat(natsMsg.sid.toString(), " ", natsMsg.subject));
//             // let asString = natsMsg.string();
//             // EXTRACT META OBJECT
//             let meta: IMessageReceivedMeta = {
//               sid: natsMsg.sid,
//               subject: natsMsg.subject,
//               action: natsMsg.headers?.get("action") ?? MessagingDefaults.ACTION,
//               correlationId: natsMsg.headers?.get("correlationId") ?? Guid.raw(),
//             };
//             if (natsMsg.headers) {
//               let dict: { [key: string]: string } = {};
//               // filter to prevent overwriting any IMessageReceivedMeta properties
//               // This will forfeit any colliding custom headers
//               // TO allow for that, consider isolating custom meta with a separate "custom" property.
//               natsMsg.headers.keys().filter(k => !Object.keys(meta).includes(k)).forEach(k => {
//                 const val = natsMsg.headers?.get(k);
//                 if (val != undefined) dict[k] = val;
//               });
//               meta = _.merge(meta, dict);
//             }
//             if (natsMsg.reply) meta.replyOn = natsMsg.reply;
//             // DESERIALIZE
//             // TODO: Consider a tryParse/else to support messages as native types (string|number|boolean)
//             let msg: TMsg;
//             try {
//               msg = this.deserialize(natsMsg);
//             } catch (err) {
//               this.logger.error(err.message);
//               if (errResponse == undefined) {
//                 errResponse = err;
//               } else {
//                 // This isnt a good spot for this error,
//                 // but if nats is already returning a transmission error,
//                 // then its very possible that a malformed message is related to the problem.
//                 errResponse.chainedError = err;
//               }
//               msg = <any>natsMsg.string() as TMsg;  // sent OUT just like it was sent IN
//             }
//             // FIRE THE PROVIDED HANDLER...
//             await handler(errResponse, msg, meta, natsMsg);
//           } catch (err) {
//             this.logger.error("Error handling message SID:".concat(natsMsg.sid.toString(), ", on ", topics, ": ", err.name ?? "", err.message ?? err.stack ?? ""));
//           } finally {
//             return;
//           }
//         }
//       };  // <--- These will likely need to be exposed very soon
//       let subx = this.cnxn.subscribe(topics, optz);
//       this.listeners.push(subx);
//       const subxId = subx.getID().toString();
//       this.logger.notice("Successfully subscribed to: ".concat("[", topics, "]", ", [subxId: ", subxId, "]"));
//       return subxId;
//     } catch (err) {
//       let errMsg = "Error subscribing: ".concat((err.name != "Error") ? err.name ?? "" : "", " ", err.message ?? err.stack ?? "");
//       this.logger.error(errMsg, err.stack);
//       throw new Error(errMsg);
//     }
//   }
//   /** Stops listening on the given topics. */
//   public async unsubscribe(topics: string, options?: { force?: boolean, subscriptionId?: string }): Promise<boolean> {
//     try {
//       let subx = this.listeners.find(sx => sx.getSubject() === topics);
//       if (subx != undefined) {
//         if (options?.force != true) {
//           await subx?.drain();
//         }
//         subx.unsubscribe();
//         this.logger.notice("Successfully unsubscribed from: ".concat("[", topics, "]"));
//         return true;
//       } else {
//         this.logger.warn("Unable to unsubscribe, no subscription found for: ".concat("[", topics, "]"));
//         return false;
//       }
//     } catch (err) {
//       this.logger.error("Error unsubscribing: ".concat(err.name ?? "", err.message ?? err.stack ?? ""));
//       return false;
//     }
//   }
//   /** THrows any errors. */
//   private deserialize<T>(raw: nats.Msg): T {
//     let output: T;
//     try {
//       if (this.settings.serializer === "string") {
//         output = <any>raw.string() as T;
//       } else {
//         let asString = raw.string();
//         output = (this.settings.serializer == 'yaml') ? YAML.parse(asString) : JSON.parse(asString) as T;
//       }
//       return output;
//     } catch (err) {
//       let msg = "Error deserializing message on ".concat(raw.subject, " to ", this.settings.serializer, ": ", err.message ?? err.stack ?? "");
//       this.logger.error(msg);
//       // output = raw.string() as T;
//       throw new Error(msg);
//     }
//   }
//   private serialize(msg: MessagePayload): nats.Payload {
//     try {
//       let payload: nats.Payload;
//       if (typeof msg === 'string') {
//         payload = msg;  // already serialized
//       } else {
//         // TODO: support a dataype or serializer override specified in the meta
//         payload = (this.settings.serializer == "yaml") ? YAML.stringify(msg) : JSON.stringify(msg);
//       }
//       // Commented out bc we're only transmitting within the local machine,
//       // so serializing to int array is just adding processing time,
//       // without any improvement to latency or security.
//       // return Buffer.from(payload, 'utf8');
//       return payload;
//     } catch (err) {
//       let msg = "Error serializing message to ".concat(this.settings.serializer, ": ", err.message ?? err.stack ?? "");
//       this.logger.error(msg, err.stack);
//       throw new Error(msg);
//     }
//   }
//   // public async publish<TMsg>(topic: string, msg: TMsg, headers?: { [name: string]: string }, replyOn?: string): Promise<void> {
//   public async publish(msg: MessagePayload, meta?: Partial<IMessageSendMeta>): Promise<void> {
//     if (this.cnxn == undefined || this.cnxn.isClosed()) {
//       await this.connect();
//     }
//     if (this.cnxn == undefined) throw new Error(`Unable to publish message: Failed connecting to nats server.`);
//     try {
//       const subject = meta?.subject ?? MessagingDefaults.SUBJECT;
//       const payload = this.serialize(msg);
//       let optz: nats.PublishOptions = {};  // <--- These will likely need to be exposed very soon
//       var ultimateMeta = (meta != undefined) ? _.omit(meta, "subject", "replyOn") : {};
//       if (ultimateMeta.action == undefined) ultimateMeta.action = MessagingDefaults.ACTION;
//       if (ultimateMeta.correlationId == undefined) ultimateMeta.correlationId = Guid.raw();
//       optz.headers = this.convertToNatsHeaders(ultimateMeta);
//       // Add auth token header if not already provided.
//       if (this.apiUserCreds?.apiToken && !optz.headers.has(NatsClient.DEFAULT_TOKEN_HEADER_PARAM)) {
//         optz.headers.set(NatsClient.DEFAULT_TOKEN_HEADER_PARAM, this.apiUserCreds.apiToken)
//       }
//       if (meta?.replyOn) optz.reply = meta.replyOn;
//       // SET IT AND FORGET IT...
//       // NOTE: to get a response, use "request()" instead of "publish()"
//       this.cnxn.publish(subject, payload, optz);
//     } catch (err) {
//       this.logger.error("Error publishing: ".concat(err.name ?? "", err.message ?? err.stack ?? ""), meta);
//     } finally {
//       return;
//     }
//   }
//   private convertToNatsHeaders(meta?: { [key: string]: any }): nats.MsgHdrsImpl {
//     let headers = new nats.MsgHdrsImpl();  // <-- is this what they want us doing here?
//     if (meta) {
//       Object.keys(meta).forEach(k => {
//         headers.append(k, meta[k]);
//       });
//     }
//     return headers;
//   }
//   public async request<TMsg extends MessagePayload, TRes extends Result>(msg: TMsg, meta?: Partial<IMessageSendMeta>, timeoutInSecs?: number): Promise<TRes> {
//     let result = new Result(false);
//     try {
//       if (this.cnxn == undefined || this.cnxn.isClosed()) {
//         await this.connect();
//       }
//       if (this.cnxn == undefined) throw new Error(`Unable to perform request: Failed connecting to nats server.`);
//       const subject = meta?.subject ?? MessagingDefaults.SUBJECT;
//       const payload = this.serialize(msg);
//       let optz: nats.RequestOptions = {
//         timeout: (timeoutInSecs ?? this.settings.requestTimeoutInSecs) * 1000
//       };  // <--- These will likely need to be exposed very soon
//       var ultimateMeta = (meta != undefined) ? _.omit(meta, "subject", "replyOn") : {};
//       if (ultimateMeta.action == undefined) ultimateMeta.action = MessagingDefaults.ACTION;
//       if (ultimateMeta.correlationId == undefined) ultimateMeta.correlationId = Guid.raw();
//       optz.headers = this.convertToNatsHeaders(ultimateMeta);
//       // Add auth token header if not already provided.
//       if (this.apiUserCreds?.apiToken && !optz.headers.has(NatsClient.DEFAULT_TOKEN_HEADER_PARAM)) {
//         optz.headers.set(NatsClient.DEFAULT_TOKEN_HEADER_PARAM, this.apiUserCreds.apiToken)
//       }
//       // TRIGGER AND WAIT FOR IT...
//       let rawRes = await this.cnxn.request(subject, payload, optz);
//       this.logger.debug("Received response to request in topic ".concat(subject, ": ", rawRes.string()));
//       result = this.deserialize<TRes>(rawRes);
//     } catch (err) {
//       result.message = "Error requesting in subject ".concat(meta?.subject ?? MessagingDefaults.SUBJECT, ": ", err.name ?? "", err.message ?? err.stack ?? "");
//       result.error = err;
//       this.logger.error(result.message, meta);
//     } finally {
//       return result as TRes;
//     }
//   }
// }
//# sourceMappingURL=nats-client.js.map