const log = require('debug')(`app:server [${process.pid}]`)
const jwtVerify = require('jsonwebtoken').verify

const LibrarySocket = require('./Library/socket')
const QueueSocket = require('./Queue/socket')
const PlayerSocket = require('./Player/socket')
const Library = require('./Library')
const Queue = require('./Queue')
const parseCookie = require('./lib/parseCookie')

const {
  LIBRARY_PUSH,
  QUEUE_PUSH,
  PLAYER_STATUS,
  PLAYER_LEAVE,
  SOCKET_AUTH_ERROR,
  _ERROR,
} = require('../constants/actions')

const handlers = {
  ...LibrarySocket,
  ...QueueSocket,
  ...PlayerSocket,
}

module.exports = function (io) {
  io.on('connection', async (sock) => {
    const { kfToken } = parseCookie(sock.handshake.headers.cookie)

    // authenticate using cookie from socket handshake
    try {
      sock.user = jwtVerify(kfToken, 'shared-secret')
    } catch (err) {
      io.to(sock.id).emit('action', {
        type: SOCKET_AUTH_ERROR,
        meta: {
          error: `${err.message} (try signing in again)`
        }
      })

      sock.user = null
      sock.disconnect()
      log(err)
      return
    }

    // attach disconnect handler
    sock.on('disconnect', (reason) => {
      if (!sock.user || !sock.user.roomId) {
        return
      }

      const room = sock.adapter.rooms[sock.user.roomId] || []

      log('%s (%s) left room %s (%s; %s in room)',
        sock.user.name, sock.id, sock.user.roomId, reason, room.length
      )

      // any players left in room?
      if (room.length && !Object.keys(room.sockets).some(id => !!io.sockets.sockets[id]._lastPlayerStatus)) {
        io.to(sock.user.roomId).emit('action', {
          type: PLAYER_LEAVE,
        })

        log('No more Players are present in room %s', sock.user.roomId)
      }
    })

    // attach action handler
    sock.on('action', async (action, acknowledge) => {
      const { type } = action
      let called = false

      if (!sock.user) {
        return acknowledge({
          type: SOCKET_AUTH_ERROR,
          meta: {
            error: 'Invalid token (try signing in again)'
          }
        })
      }

      if (typeof handlers[type] === 'function') {
        called = true

        try {
          await handlers[type](sock, action, acknowledge)
        } catch (err) {
          log(err)
          const error = `Error in handler ${type}: ${err.message}`

          return acknowledge({
            type: type + _ERROR,
            meta: {
              error,
            }
          })
        }
      }

      if (!called) {
        log('warning: no handler for action type: %s', type)
      }
    })

    // add user to the room on their jwt
    sock.join(sock.user.roomId)

    const room = sock.adapter.rooms[sock.user.roomId]

    // if there's a player in room, emit its last known status
    const lastStatusSocket = Object.keys(room.sockets).find(id => !!io.sockets.sockets[id]._lastPlayerStatus)

    if (lastStatusSocket) {
      io.to(sock.id).emit('action', {
        type: PLAYER_STATUS,
        payload: io.sockets.sockets[lastStatusSocket]._lastPlayerStatus,
      })
    }

    log('%s (%s) joined room %s (%s in room)',
      sock.user.name, sock.id, sock.user.roomId, room.length
    )

    // send library and queue
    try {
      io.to(sock.id).emit('action', {
        type: QUEUE_PUSH,
        payload: await Queue.getQueue(sock.user.roomId),
      })

      io.to(sock.id).emit('action', {
        type: LIBRARY_PUSH,
        payload: await Library.get(),
      })
    } catch (err) {
      log(err)
    }
  })
}

@@ -1888,33 +1888,8 @@
 tion
-%0A      let called = false
 %0A%0A  
@@ -2114,17 +2114,17 @@
 s%5Btype%5D 
-=
+!
 == 'func
@@ -2144,25 +2144,85 @@
     
-called = true%0A%0A  
+log('warning: no handler for action type: %25s', type)%0A        return%0A      %7D%0A%0A
     
@@ -2237,18 +2237,16 @@
         
-  
 await ha
@@ -2291,18 +2291,16 @@
 )%0A      
-  
 %7D catch 
@@ -2311,34 +2311,32 @@
 ) %7B%0A        
-  
 log(err)
 %0A          c
@@ -2327,75 +2327,8 @@
 err)
-%0A          const error = %60Error in handler $%7Btype%7D: $%7Berr.message%7D%60
 %0A%0A  
@@ -2329,26 +2329,24 @@
 r)%0A%0A        
-  
 return ackno
@@ -2346,34 +2346,32 @@
 n acknowledge(%7B%0A
-  
           type: 
@@ -2387,34 +2387,32 @@
 RROR,%0A          
- 
- 
 meta: %7B%0A        
@@ -2419,30 +2419,58 @@
     
-  
 error
-,%0A            %7D
+: %60Error in handler $%7Btype%7D: $%7Berr.message%7D%60,
 %0A   
@@ -2473,25 +2473,24 @@
 %0A          %7D
-)
 %0A        %7D%0A 
@@ -2491,98 +2491,8 @@
    %7D
-%0A      %7D%0A%0A      if (!called) %7B%0A        log('warning: no handler for action type: %25s', type
 )%0A  

Refactor socket handler