const { getBoothData } = require('./booth');
const { serializePlaylist } = require('../utils/serialize');

async function getFirstItem(user, activePlaylist) {
  try {
    const playlist = await activePlaylist;
    if (playlist) {
      const item = await playlist.getItemAt(0);
      return item;
    }
  } catch (e) {
    // Nothing
  }
  return null;
}

function toInt(str) {
  if (typeof str !== 'string') return 0;
  if (!/^\d+$/.test(str)) return 0;
  return parseInt(str, 10);
}

async function getOnlineUsers(uw) {
  const { User } = uw.models;

  const userIDs = await uw.redis.lrange('users', 0, -1);
  return User.find({ _id: { $in: userIDs } });
}

async function getGuestsCount(uw) {
  const guests = await uw.redis.get('http-api:guests');
  return toInt(guests);
}

async function getState(req) {
  const uw = req.uwave;
  const { authRegistry } = req.uwaveHttp;
  const { passport } = uw;
  const { user } = req;

  const motd = uw.motd.get();
  const users = getOnlineUsers(uw);
  const guests = getGuestsCount(uw);
  const roles = uw.acl.getAllRoles();
  const booth = getBoothData(uw);
  const waitlist = uw.waitlist.getUserIDs();
  const waitlistLocked = uw.waitlist.isLocked();
  const activePlaylist = user ? user.getActivePlaylist() : null;
  const playlists = user ? user.getPlaylists() : null;
  const firstActivePlaylistItem = activePlaylist ? getFirstItem(user, activePlaylist) : null;
  const socketToken = user ? authRegistry.createAuthToken(user) : null;
  const authStrategies = passport.strategies();
  const time = Date.now();

  const stateShape = {
    motd,
    user,
    users,
    guests,
    roles,
    booth,
    waitlist,
    waitlistLocked,
    activePlaylist: activePlaylist
      ? activePlaylist.then((p) => (p ? p.id : null))
      : null,
    firstActivePlaylistItem,
    playlists,
    socketToken,
    authStrategies,
    time,
  };

  const stateKeys = Object.keys(stateShape);
  const stateValues = await Promise.all(Object.values(stateShape));

  const state = {};
  for (let i = 0; i < stateKeys.length; i += 1) {
    state[stateKeys[i]] = stateValues[i];
  }

  if (state.playlists) {
    state.playlists = state.playlists.map(serializePlaylist);
  }

  return state;
}

exports.getState = getState;

@@ -1,16 +1,70 @@
+const debug = require('debug')('uwave:http-api:now');%0A
 const %7B getBooth
@@ -88,24 +88,24 @@
 './booth');%0A
-
 const %7B seri
@@ -1246,20 +1246,18 @@
 ed();%0A  
-cons
+le
 t active
@@ -1600,24 +1600,733 @@
 ate.now();%0A%0A
+  if (activePlaylist != null) %7B%0A    activePlaylist = activePlaylist%0A      .then((playlist) =%3E (playlist ? playlist.id : null))%0A      .catch((err) =%3E %7B%0A        // If the playlist was not found, our database is inconsistent. A deleted or nonexistent%0A        // playlist should never be listed as the active playlist. Most likely this is not the%0A        // user's fault, so we should not error out on %60/api/now%60. Instead, pretend they don't have%0A        // an active playlist at all. Clients can then let them select a new playlist to activate.%0A        if (err.code === 'NOT_FOUND') %7B%0A          debug('The active playlist does not exist', err);%0A          return null;%0A        %7D%0A        throw err;%0A      %7D);%0A  %7D%0A%0A
   const stat
@@ -2435,16 +2435,16 @@
 Locked,%0A
+
     acti
@@ -2457,91 +2457,8 @@
 list
-: activePlaylist%0A      ? activePlaylist.then((p) =%3E (p ? p.id : null))%0A      : null
 ,%0A  

Handle case where active playlist does not exist. (#381)