/** Class contains logic towards outgoing OSC communications. */
import { Client, Message } from 'node-osc';

export class OSCIntegration {
  constructor() {
    // OSC Client
    this.ADDRESS = '/ontime';
    this.oscClient = null;
  }

  /**
   * @description Returns list of implemented messages
   * @returns {object} implemented messages
   */
  get implemented() {
    return {
      play: 'play',
      pause: 'pause',
      stop: 'stop',
      previous: 'prev',
      next: 'next',
      reload: 'reload',
      finished: 'finished',
      time: 'time',
      overtime: 'overtime',
      title: 'title',
      presenter: 'presenter',
    };
  }

  /**
   * @description Initializes oscClient
   * @param {object} oscConfig - oscClient configuration options
   * @param {string} oscConfig.ip - oscClient object
   * @param {number} oscConfig.port - OSC Destination Port
   */
  init(oscConfig) {
    const { ip, port } = oscConfig;
    try {
      this.oscClient = new Client(ip, port);
      return {
        success: true,
        message: `Initialised OSC Client at ${ip}:${port}`,
      };
    } catch (error) {
      this.oscClient = null;
      return {
        success: true,
        message: `Failed initialising OSC Client: ${error}`,
      };
    }
  }

  /**
   * @description Sends osc  from predefined messages
   * @param {string} messageType - message to be sent
   * @param {string} [payload] - optional payload required in some message types
   */
  async send(messageType, payload) {
    const reply = {
      success: true,
      message: 'OSC Message sent',
    };

    if (this.oscClient == null) {
      reply.success = false;
      reply.message = 'Client not initialised';
      return reply;
    }

    if (messageType == null) {
      reply.success = false;
      reply.message = 'Message undefined';
      return reply;
    }

    // only specify special cases
    switch (payload) {
      case 'overtime':
        // Whether timer is negative
        this.oscClient.send(`${this.ADDRESS}/overtime`, payload, (err) => {
          if (err) {
            reply.success = false;
            reply.message = err;
          }
        });
        break;

      case 'title':
        if (payload != null && payload !== '') {
          // Send Title of current event
          this.oscClient.send(`${this.ADDRESS}/title`, payload, (err) => {
            if (err) {
              reply.success = false;
              reply.message = err;
            }
          });
        } else {
          reply.success = false;
          reply.message = 'Missing message data';
        }
        break;

      case 'presenter':
        if (payload != null && payload !== '') {
          // Send presenter data on current event
          this.oscClient.send(`${this.ADDRESS}/presenter`, payload, (err) => {
            if (err) {
              reply.success = false;
              reply.message = err;
            }
          });
        } else {
          reply.success = false;
          reply.message = 'Missing message data';
        }
        break;

      default:
        // catch all for messages, allows to add new messages
        // but should be used with the integrations definition
        // eslint-disable-next-line no-case-declarations
        const message = new Message(`${this.ADDRESS}/${messageType}`);
        if (payload != null) message.append(payload);
        this.oscClient.send(message, (err) => {
          if (err) {
            reply.success = false;
            reply.message = err;
          }
        });
        break;
    }
    return reply;
  }

  shutdown() {
    // Shutdown client object
    this.oscClient.close();
    this.oscClient = null;
  }
}
