/*!
 * Buttplug JS Source Code File - Visit https://buttplug.io for more info about
 * the project. Licensed under the BSD 3-Clause license. See LICENSE file in the
 * project root for full license information.
 *
 * @copyright Copyright (c) Nonpolynomial Labs LLC. All rights reserved.
 */

import { ButtplugMessage } from './core/Messages';
import { IButtplugClientConnector } from './client/IButtplugClientConnector';
import { EventEmitter } from 'eventemitter3';

export * from './client/ButtplugClient';
export * from './client/ButtplugClientDevice';
export * from './client/ButtplugBrowserWebsocketClientConnector';
export * from './client/ButtplugNodeWebsocketClientConnector';
export * from './client/ButtplugClientConnectorException';
export * from './utils/ButtplugMessageSorter';
export * from './client/ButtplugClientDeviceCommand';
export * from './client/ButtplugClientDeviceFeature';
export * from './client/IButtplugClientConnector';
export * from './core/Messages';
export * from './core/Logging';
export * from './core/Exceptions';

export class ButtplugWasmClientConnector
  extends EventEmitter
  implements IButtplugClientConnector
{
  private static _loggingActivated = false;
  private static wasmInstance;
  private _connected: boolean = false;
  private client;
  private serverPtr;

  constructor() {
    super();
  }

  public get Connected(): boolean {
    return this._connected;
  }

  private static maybeLoadWasm = async () => {
    if (ButtplugWasmClientConnector.wasmInstance == undefined) {
      ButtplugWasmClientConnector.wasmInstance = await import(
        '../wasm/index.js'
      );
    }
  };

  public static activateLogging = async (logLevel: string = 'debug') => {
    await ButtplugWasmClientConnector.maybeLoadWasm();
    if (this._loggingActivated) {
      console.log('Logging already activated, ignoring.');
      return;
    }
    console.log('Turning on logging.');
    ButtplugWasmClientConnector.wasmInstance.buttplug_activate_env_logger(
      logLevel,
    );
  };

  public initialize = async (): Promise<void> => {};

  public connect = async (): Promise<void> => {
    await ButtplugWasmClientConnector.maybeLoadWasm();
    this.client =
      ButtplugWasmClientConnector.wasmInstance.buttplug_create_embedded_wasm_server(
        (msgs) => {
          this.emitMessage(msgs);
        },
        this.serverPtr,
      );
    this._connected = true;
  };

  public disconnect = async (): Promise<void> => {};

  public send = (msg: ButtplugMessage): void => {
    ButtplugWasmClientConnector.wasmInstance.buttplug_client_send_json_message(
      this.client,
      new TextEncoder().encode('[' + JSON.stringify(msg) + ']'),
      (output) => {
        this.emitMessage(output);
      },
    );
  };

  private emitMessage = (msg: Uint8Array) => {
    const str = new TextDecoder().decode(msg);
    const msgs: ButtplugMessage[] = JSON.parse(str);
    this.emit('message', msgs);
  };
}
