/* eslint-disable
    camelcase,
    node/handle-callback-err,
    max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
 * decaffeinate suggestions:
 * DS102: Remove unnecessary code created because of implicit returns
 * DS207: Consider shorter variations of null checks
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */
let rclient_secondary
const OError = require('@overleaf/o-error')
const Settings = require('settings-sharelatex')
const request = require('request').defaults({ timeout: 30 * 1000 })
const RedisWrapper = require('../../infrastructure/RedisWrapper')
const rclient = RedisWrapper.client('clsi_cookie')
if (Settings.redis.clsi_cookie_secondary != null) {
  rclient_secondary = RedisWrapper.client('clsi_cookie_secondary')
}
const Cookie = require('cookie')
const logger = require('logger-sharelatex')

const clsiCookiesEnabled =
  (Settings.clsiCookie != null ? Settings.clsiCookie.key : undefined) != null &&
  Settings.clsiCookie.key.length !== 0

module.exports = function (backendGroup) {
  return {
    buildKey(project_id) {
      if (backendGroup != null) {
        return `clsiserver:${backendGroup}:${project_id}`
      } else {
        return `clsiserver:${project_id}`
      }
    },

    _getServerId(project_id, callback) {
      if (callback == null) {
        callback = function (err, serverId) {}
      }
      return rclient.get(this.buildKey(project_id), (err, serverId) => {
        if (err != null) {
          return callback(err)
        }
        if (serverId == null || serverId === '') {
          return this._populateServerIdViaRequest(project_id, callback)
        } else {
          return callback(null, serverId)
        }
      })
    },

    _populateServerIdViaRequest(project_id, callback) {
      if (callback == null) {
        callback = function (err, serverId) {}
      }
      const url = `${Settings.apis.clsi.url}/project/${project_id}/status`
      return request.post(url, (err, res, body) => {
        if (err != null) {
          OError.tag(err, 'error getting initial server id for project', {
            project_id
          })
          return callback(err)
        }
        return this.setServerId(project_id, res, function (err, serverId) {
          if (err != null) {
            logger.warn(
              { err, project_id },
              'error setting server id via populate request'
            )
          }
          return callback(err, serverId)
        })
      })
    },

    _parseServerIdFromResponse(response) {
      const cookies = Cookie.parse(
        (response.headers['set-cookie'] != null
          ? response.headers['set-cookie'][0]
          : undefined) || ''
      )
      return cookies != null ? cookies[Settings.clsiCookie.key] : undefined
    },

    setServerId(project_id, response, callback) {
      if (callback == null) {
        callback = function (err, serverId) {}
      }
      if (!clsiCookiesEnabled) {
        return callback()
      }
      const serverId = this._parseServerIdFromResponse(response)
      if (serverId == null) {
        // We don't get a cookie back if it hasn't changed
        return rclient.expire(
          this.buildKey(project_id),
          Settings.clsiCookie.ttl,
          callback
        )
      }
      if (rclient_secondary != null) {
        this._setServerIdInRedis(rclient_secondary, project_id, serverId)
      }
      return this._setServerIdInRedis(rclient, project_id, serverId, err =>
        callback(err, serverId)
      )
    },

    _setServerIdInRedis(rclient, project_id, serverId, callback) {
      if (callback == null) {
        callback = function (err) {}
      }
      rclient.setex(
        this.buildKey(project_id),
        Settings.clsiCookie.ttl,
        serverId,
        callback
      )
    },

    clearServerId(project_id, callback) {
      if (callback == null) {
        callback = function (err) {}
      }
      if (!clsiCookiesEnabled) {
        return callback()
      }
      return rclient.del(this.buildKey(project_id), callback)
    },

    getCookieJar(project_id, callback) {
      if (callback == null) {
        callback = function (err, jar) {}
      }
      if (!clsiCookiesEnabled) {
        return callback(null, request.jar())
      }
      return this._getServerId(project_id, (err, serverId) => {
        if (err != null) {
          OError.tag(err, 'error getting server id', {
            project_id
          })
          return callback(err)
        }
        const serverCookie = request.cookie(
          `${Settings.clsiCookie.key}=${serverId}`
        )
        const jar = request.jar()
        jar.setCookie(serverCookie, Settings.apis.clsi.url)
        return callback(null, jar)
      })
    }
  }
}
