import { addTorrent, updateTorrent, removeTorrent, deleteTorrent } from '../actions/torrent-actions'
import { updateClient } from '../actions/client-actions'
import WebTorrent from 'webtorrent'

const MAX_RETRIES = 5
const RETRY_INTERVAL = 20000

let updateTimer = null
let client      = null

const updateClientState = (store) => {
  store.dispatch(updateClient({
    downloadSpeed: client.downloadSpeed, 
    uploadSpeed: client.uploadSpeed
  }))
  updateTimer = setTimeout(updateClientState.bind(updateClientState, store), 1000)
}

const setTorrentTimeout = function (torrent, store, magnetUri) {
  return setTimeout(() => {
    client.remove(torrent.infoHash, (err) => {
      this.retries += 1
      if (this.retries > MAX_RETRIES) return store.dispatch(deleteTorrent(torrent.infoHash)); // TODO: report error
      addTorrentToClient.call(this, store, magnetUri)
    })
  }, RETRY_INTERVAL)
}

const addTorrentToClient = function (store, magnetUri) {
  this.retries = this.retries || 0
  const torrent = client.add(magnetUri, {path: "./"}, (torrent) => {
    torrent.on("download", store.dispatch.bind(store, updateTorrent(torrent)))
    torrent.on("upload", store.dispatch.bind(store, updateTorrent(torrent)))
    torrent.on("done", store.dispatch.bind(store, updateTorrent(torrent)))
    clearTimeout(timeout)
  })
  const timeout = setTorrentTimeout.call(this, torrent, store, magnetUri)
}

const removeTorrentFromClient = (store, torrentId) => {
  client.remove(torrentId, (err) => {
    store.dispatch(deleteTorrent(torrentId))
  })
}

export function torrentClient(store) {
  return next => action => {
    const result = next(action)
    if (client) {
      switch (action.type) {
        case 'ADD_TORRENT':
          addTorrentToClient.call({}, store, action.magnetUri)
          break
        case 'REMOVE_TORRENT':
          removeTorrentFromClient(store, action.data)
          break
      }
    }
    return result
  }
}

export default function (store) {
  client = new WebTorrent({maxConns: 10})
  updateClientState(store)
}

@@ -206,16 +206,19 @@
 RETRIES 
+   
 = 5%0Acons
@@ -242,17 +242,16 @@
 = 20000%0A
-%0A
 let upda
@@ -258,16 +258,21 @@
 teTimer 
+     
 = null%0Al
@@ -282,24 +282,29 @@
 client      
+     
 = null%0A%0Acons
@@ -544,373 +544,8 @@
 %0A%7D%0A%0A
-const setTorrentTimeout = function (torrent, store, magnetUri) %7B%0A  return setTimeout(() =%3E %7B%0A    client.remove(torrent.infoHash, (err) =%3E %7B%0A      this.retries += 1%0A      if (this.retries %3E MAX_RETRIES) return store.dispatch(deleteTorrent(torrent.infoHash)); // TODO: report error%0A      addTorrentToClient.call(this, store, magnetUri)%0A    %7D)%0A  %7D, RETRY_INTERVAL)%0A%7D%0A%0A
 cons
@@ -989,58 +989,81 @@
 setT
-orrentTimeout.call
+imeout(removeTorrentFromClient.bind
 (this, 
+s
 tor
-r
 e
-nt
 , 
-s
 tor
-e, magnetUri
+rent), RETRY_INTERVAL
 )%0A%7D%0A
@@ -1094,16 +1094,25 @@
 Client =
+ function
  (store,
@@ -1123,54 +1123,378 @@
 rent
-Id) =%3E %7B%0A  client.remove(torrentId, (err) =%3E %7B
+) %7B%0A  const torrentId = typeof torrent === %22string%22 ? torrent : torrent.infoHash%0A  client.remove(torrentId, (err) =%3E %7B%0A    if (this.retries !== undefined) %7B%0A      this.retries += 1%0A      if (this.retries %3E MAX_RETRIES) return store.dispatch(deleteTorrent(torrent.infoHash)) // TODO: report error%0A      return addTorrentToClient.call(this, store, torrent.magnetURI)%0A    %7D
 %0A   
@@ -1658,24 +1658,16 @@
 (client)
- %7B%0A     
  switch 
@@ -1678,26 +1678,24 @@
 ion.type) %7B%0A
-  
       case '
@@ -1716,18 +1716,16 @@
         
-  
 addTorre
@@ -1773,34 +1773,30 @@
 ri)%0A        
-  
 break%0A
-  
       case '
@@ -1820,18 +1820,16 @@
         
-  
 removeTo
@@ -1839,25 +1839,34 @@
 ntFromClient
-(
+.call(%7B%7D, 
 store, actio
@@ -1885,24 +1885,14 @@
     
-  
 break%0A
-      %7D%0A
     

refactor middleware