import Ember from 'ember';
import run from 'ember-runloop';

const { Test: { registerAsyncHelper } } = Ember;

const READY_STATES = {
  OPEN: 1,
  CLOSED: 3
};

let openWebSockets = [];
let receivedMessages = [];
let originalWebSocket;

export const ircURL = 'wss://irc-ws.chat.twitch.tv:443';

export function setup() {
  originalWebSocket = window.WebSocket;

  window.WebSocket = function(url) {
    openWebSockets.push(this);

    this.url = url;
    this.readyState = READY_STATES.OPEN;

    this.send = (data) => {
      if (this.readyState === READY_STATES.OPEN) {
        receivedMessages.push({ socket: this, data });
      }
    };

    this.close = () => {
      this.readyState = READY_STATES.CLOSED;
    };
  };

  window.WebSocket.OPEN = READY_STATES.OPEN;
  window.WebSocket.CLOSED = READY_STATES.CLOSED;
}

export function teardown() {
  openWebSockets.forEach((ws) => ws.close());

  openWebSockets.length = 0;
  receivedMessages.length = 0;

  window.WebSocket = originalWebSocket;
}

export function ircSocketMessages() {
  return receivedMessages.filter((message) => message.socket.url === ircURL);
}

function generateUserNotice({ channel, login, msgId, params, systemMsg, text }) {
  // Example USERNOTICE command:
  // @badges=staff/1,broadcaster/1,turbo/1;color=#008000;display-name=NotFrank;emotes=;mod=0;msg-id=resub;msg-param-months=6;room-id=20624989;subscriber=0;system-msg=NotFrank\shas\ssubscribed\sfor\s6\smonths!;login=notfrank;turbo=1;user-id=20624989;user-type=staff :tmi.twitch.tv USERNOTICE #NotFrank :Great stream -- keep it up!

  let tags = `msg-id=${ msgId };system-msg=${ systemMsg.replace(/\s/g, '\\s') };login=${ login };`;

  for (let key in params) {
    tags = `${ tags }msg-param-${ key }=${ params[key] };`;
  }

  // '@' is important for TMI parsing!
  return `@${ tags }user-type=staff :tmi.twitch.tv USERNOTICE #${ channel } :${ text }`;
}

function generatePrivateMessage({ channel, from, text }) {
  // Example PRIVMSG command:
  // @color=#2E8B57;display-name=iezerdev;emotes=;mod=0;room-id=118192158;subscriber=0;turbo=0;user-id=118192158;user-type= :iezerdev!iezerdev@iezerdev.tmi.twitch.tv PRIVMSG #iezerdev :test

  return `:${ from } PRIVMSG #${ channel } :${ text }`;
}

function generateHostTargetMessage({ hostTarget, target, numViewers }) {
  // :tmi.twitch.tv HOSTTARGET #mixnic_twitch1 :mixonic_ -
  return `:tmi.twitch.tv HOSTTARGET #${hostTarget} :${target} ${numViewers || '-'}`;
}

registerAsyncHelper('sendIRCMessage', function(app, messageObject) {
  let message;

  switch (messageObject.command) {
    case 'USERNOTICE':
      message = generateUserNotice(messageObject);
      break;
    case 'HOSTTARGET':
      message = generateHostTargetMessage(messageObject);
      break;
    default:
      message = generatePrivateMessage(messageObject);
      break;
  }

  let sendIfSocket = () => {
    let start = new Date();
    let ircSocket = openWebSockets.find((socket) => socket.url === ircURL);

    if (ircSocket) {
      ircSocket.onmessage({ data: message });
    } else if ((new Date()) - start > 2000) {
      throw new Error(`Expected to find an open websocket with url ${ ircURL }, found none after 2 seconds`);
    } else {
      run.later(sendIfSocket, 80);
    }
  };

  sendIfSocket();

  return wait();
});
