# Author: VTEX

NodeCache = require 'node-cache'
VTEX = require 'vtex-node-sdk'
request = require 'request'
Q = require 'q'

FIVE_MINUTES = 5 * 60

IAMClient = VTEX.IAM

#######################################################
#                                                     #
#                                                     #
# This code is broken and needs a complete rewrite!!! #
#                                                     #
#                                                     #
#######################################################
class SetIamCookie

  constructor: (options) ->
    @options = options
    @cache = new NodeCache(stdTTL: @options.ttl or FIVE_MINUTES)
    @iam = new IAMClient()
    @authCookieName = "VtexAuthCookie"

  ########################
  # Handler              #
  ########################

  handler: (req, res, next) =>
    return next() if @options.utils.isAdmin(req, @options) is false
    return next() if req.url.indexOf('/admin/logout') isnt -1

    expireCookie = (token) =>
      @options.logger.debug('expireCookie')
      return _setCookie(res, @authCookieName, token, -1)

    setCookie = (token) =>
      @options.logger.debug('setCookie')
      return _setCookie(res, @authCookieName, token, 1)

    setCache = (token) =>
      @options.logger.debug('setCache')
      @cache.set req.cookies.VtexIdclientAutCookie, token
      return token

    refreshPage = =>
      @options.logger.debug('refreshPage')
      res.statusCode = 302
      res.setHeader 'Location', "http://#{req.headers.location}#{req.url}"

    getIamToken = =>
      @options.logger.debug('getIamToken')
      deferToken = (response, token) -> return token
      @iam.getVtexAuthToken(req.vtex.store, req.cookies.VtexIdclientAutCookie).spread(deferToken)

    validateCachedToken = (token) =>
      @options.logger.debug('validateCachedToken')
      validate = (value) ->
        return value[req.cookies.VtexIdclientAutCookie] is token

      Q.ninvoke(@cache, 'get', [req.cookies.VtexIdclientAutCookie]).then(validate)

    cleanCache = =>
      @options.logger.debug('cleanCache')
      Q.ninvoke(@cache, 'del', [req.cookies.VtexIdclientAutCookie])

    #
    # First and second logic layers
    #

    isCached = (cookie) =>
      @options.logger.debug('isCached')
      deferred = Q.defer()
      if cookie
        deferred.resolve(cookie)
        return deferred.promise
          .then validateCachedToken
          .then (isValid) -> unless isValid then return cleanCache
      else
        deferred.resolve()
        return deferred.promise
          .then cleanCache
          .then refreshPage

    isntCached = (cookie) =>
      @options.logger.debug('isntCached')
      deferred = Q.defer()
      if cookie
        deferred.resolve(cookie)
        return deferred.promise
          .then expireCookie
          .then refreshPage
      else
        deferred.resolve()
        return deferred.promise
          .then getIamToken
          .then setCookie
          .then setCache

    verifyVtexAuthCookie = (strategy) -> strategy(req.cookies.VtexAuthCookie or null)

    verifyCache = (value) =>
      @options.logger.debug('verifyCache')

      deferred = Q.defer()

      if value[req.cookies.VtexIdclientAutCookie]?
        deferred.resolve(isCached)
      else
        deferred.resolve(isntCached)

      return deferred.promise

    #
    # Promise calls
    #

    Q.ninvoke(@cache, 'get', [req.cookies.VtexIdclientAutCookie])
      .then(verifyCache)
      .then(verifyVtexAuthCookie)
      .then(-> next())
      .catch(console.error)

  ########################
  # Private function     #
  ########################

  _setCookie = (res, cookieName, cookieValue, relativeExpirationDays = 0) ->
    date = new Date()
    relativeExpDate = date.getDate() + relativeExpirationDays
    date.setDate(relativeExpDate)
    expireDate = date.toGMTString()
    cookieString = "#{cookieName}=#{cookieValue}; Expires=#{expireDate};"
    res.setHeader("Set-Cookie", cookieString)
    return cookieValue

module.exports = SetIamCookie
