'use strict';

var atoa = require('atoa');
var serialization = require('./serialization');
var emitter = require('contra/emitter');

module.exports = createChannel;

function createChannel () {
  var internalEmitter = emitter();
  var api = {
    on: selfed('on'),
    once: selfed('once'),
    off: selfed('off'),
    broadcast: broadcastToPages,
    emit: replyToClient
  };

  self.addEventListener('message', postFromPage);

  return api;

  function selfed (method) {
    return function selfish () {
      internalEmitter[method].apply(null, arguments);
      return api;
    };
  }

  function postFromPage (e) {
    var context = {
      reply: replyToPage(e)
    };
    serialization.emission(internalEmitter, context)(e);
  }

  function broadcastToPages (type) {
    var payload = atoa(arguments, 1);
    return self.clients.matchAll().then(gotClients);
    function gotClients (clients) {
      return clients.map(emitToClient);
    }
    function emitToClient (client) {
      return client.postMessage({ type: type, payload: payload, __broadcast: true });
    }
  }

  function replyTo (client) {
    var payload = serialization.parsePayload(atoa(arguments, 1));
    return client.postMessage(payload);
  }

  function replyToPage (e) {
    return replyTo.bind(null, e.ports[0]);
  }

  function replyToClient (clientId) {
    return self.clients.matchAll().then(findClientById(clientId)).then(replyTo);
  }

  function findClientById (clientId) {
    return function findClientByIdFromList (clients) {
      for (var i = 0; i < clients.length; i++) {
        if (clients[i].id === clientId) {
          return clients[i];
        }
      }
      return null;
    };
  }
}

@@ -1322,32 +1322,65 @@
 nt (clientId) %7B%0A
+    const args = atoa(arguments)%0A
     return self.
@@ -1443,12 +1443,103 @@
 eply
-To
 );
+%0A    function reply (client) %7B%0A      args%5B0%5D = client;%0A      replyTo.apply(this, args);%0A    %7D
 %0A  %7D

Fix reply model