var http = require('http')
var https = require('https')
var corsify = require('corsify')
var collect = require('stream-collector')
var pump = require('pump')
var iterate = require('random-iterate')
var limiter = require('size-limit-stream')
var eos = require('end-of-stream')

var flushHeaders = function (res) {
  if (res.flushHeaders) {
    res.flushHeaders()
  } else {
    if (!res._header) res._implicitHeader()
    res._send('')
  }
}

module.exports = function (opts) {
  var channels = {}
  var maxBroadcasts = (opts && opts.maxBroadcasts) || Infinity
  var subs = 0

  var get = function (channel) {
    if (channels[channel]) return channels[channel]
    channels[channel] = {name: channel, subscribers: []}
    return channels[channel]
  }

  var cors = corsify({
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
    'Access-Control-Allow-Headers': 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Authorization'
  })

  var onRequest = cors(function (req, res) {
    if (req.url === '/') {
      res.end(JSON.stringify({name: 'signalhub', version: require('./package').version, subscribers: subs}, null, 2) + '\n')
      return
    }

    if (req.url.slice(0, 4) !== '/v1/') {
      res.statusCode = 404
      res.end()
      return
    }

    var name = req.url.slice(4).split('?')[0]

    if (req.method === 'POST') {
      collect(pump(req, limiter(64 * 1024)), function (err, data) {
        if (err) return res.end()
        if (!channels[name]) return res.end()
        var channel = get(name)

        server.emit('publish', channel.name, data)
        data = Buffer.concat(data).toString()

        var ite = iterate(channel.subscribers)
        var next
        var cnt = 0

        while ((next = ite()) && cnt++ < maxBroadcasts) {
          next.write('data: ' + data + '\n\n')
        }

        res.end()
      })
      return
    }

    if (req.method === 'GET') {
      res.setHeader('Content-Type', 'text/event-stream; charset=utf-8')
      res.setTimeout(30000, ontimeout)

      var app = name.split('/')[0]
      var channelNames = name.slice(app.length + 1)

      channelNames.split(',').forEach(function (channelName) {
        var channel = get(app + '/' + channelName)
        server.emit('subscribe', channel.name)
        channel.subscribers.push(res)
        subs++
        eos(res, function () {
          subs--
          var i = channel.subscribers.indexOf(res)
          if (i > -1) channel.subscribers.splice(i, 1)
          if (!channel.subscribers.length && channel === channels[channel.name]) delete channels[channel.name]
        })
      })

      flushHeaders(res)
      return
    }

    res.statusCode = 404
    res.end()
  })

  var useHttps = !!(opts && opts.key && opts.cert)
  var server = useHttps ? https.createServer(opts) : http.createServer()
  server.on('request', onRequest)

  return server
}

function ontimeout () {
  var flushed = this.write(':heartbeat signal\n\n')
  if (!flushed) this.connection.destroy()
}

@@ -658,33 +658,23 @@
 el%5D%0A    
-channels%5Bchannel%5D
+var sub
  = %7Bname
@@ -699,17 +699,123 @@
 bers: %5B%5D
-%7D
+, heartbeat: null%7D%0A    sub.heartbeat = setInterval(heartbeater(sub), 30 * 1000)%0A    channels%5Bchannel%5D = sub
 %0A    ret
@@ -2124,47 +2124,8 @@
 -8')
-%0A      res.setTimeout(30000, ontimeout)
 %0A%0A  
@@ -2658,16 +2658,75 @@
 l.name%5D)
+ %7B%0A            clearInterval(channel.heartbeat)%0A           
  delete 
@@ -2748,16 +2748,28 @@
 l.name%5D%0A
+          %7D%0A
         
@@ -2994,16 +2994,17 @@
 erver()%0A
+%0A
   server
@@ -3033,72 +3033,338 @@
 st)%0A
-%0A  return server%0A%7D%0A%0Afunction ontimeout () %7B%0A  var flushed = this
+  server.on('close', function () %7B%0A    var names = Object.keys(channels)%0A    for (var i = 0; i %3C names.length; i++) %7B%0A      clearInterval(channels%5Bnames%5Bi%5D%5D.heartbeat)%0A    %7D%0A  %7D)%0A%0A  return server%0A%7D%0A%0Afunction heartbeater (sub) %7B%0A  return function () %7B%0A    for (var i = 0; i %3C sub.subscribers.length; i++) %7B%0A      sub.subscribers%5Bi%5D
 .wri
@@ -3397,46 +3397,14 @@
 )%0A  
+ 
-if (!flushed) this.connection.destroy()
+ %7D%0A  %7D
 %0A%7D%0A

change heartbeating