###
Module dependencies.
###
NodeCache = require 'node-cache'
request = require 'request'
fs = require 'fs'
colors = require 'colors'
url = require 'url'

WhiteList = require '../libs/white-list'
Logger = require '../libs/logger'
getRedirectSettings = require '../libs/return-url'
parseCookies = require '../libs/cookie-parser'
redirect = require '../libs/redirect'
httpErrorResponse = require '../libs/http-errors'

authenticationHandler = (options = {}) ->
  FIVE_MINUTES = 5 * 60
  options.verbose or= false
  options.ttl or= FIVE_MINUTES
  options.redirectUrl or= '/admin/login?ReturnUrl='
  options.logoutUrl or= '/admin/logout'
  options.replaceWhiteList or= false
  options.addToWhiteList or= []
  options.useReturnUrl = true if not options.returnUrl?
  options.verbose or= false
  options.verbosityLevel = 1 if not options.verbosityLevel?

  logger = new Logger(options)

  logger.logConfigOptions()

  logger.logWhiteListProcedure()
  whiteList = new WhiteList options.replaceWhiteList
  whiteList.addToPublicUris options.redirectUrl
  whiteList.addToPublicUris options.addToWhiteList

  logger.logWhiteListConfiguration(whiteList)

  logger.logCacheSetupProcedure()
  cache = new NodeCache stdTTL: options.ttl

  (req, res, next) ->

    req.vtex or= {}

    unauthorized = httpErrorResponse res, 401
    forbidden = httpErrorResponse res, 403

    # Bypasses authentication if requesting public resource
    if whiteList.isInWhiteList(req.url) and req.url.indexOf(options.logoutUrl) is -1
      logger.logWhiteListHit(req.url)
      return next()

    # Gets VTEX ID Return Url
    logger.logRedirectUrlSetupProcedure()
    redirectSettings = getRedirectSettings options, req.url
    logger.logRedirectUrl(redirectSettings.redirectUrl)

    # Let user go to logout page
    if req.url.indexOf(options.logoutUrl) isnt -1
      logger.logUserLogout()
      urlParams = url.parse(req.url, true)

      if req.headers.originalHost?
        referer = req.headers.originalHost
      else
        referer = req.headers.host
      refererRegexp = /([a-zA-Z0-9-$_.+]*)/
      match = refererRegexp.exec(referer)
      domain = match[1]

      expiredDate = new Date()
      expiredDate.setYear(2000)
      expired = "VtexIdclientAutCookie=; domain=#{domain}; expires=#{expiredDate.toISOString()}; path=/"
      res.setHeader('Set-Cookie', expired)

      urlToRedirect = encodeURIComponent(urlParams.query.redirectUrl)
      targetUrl = "https://vtexid.vtex.com.br/VtexIdAuthSite/Logout.aspx?urlToRedirect=#{urlToRedirect}"
      return redirect(res, targetUrl)

    # Parses cookies from request
    logger.logCookieParsingProcedure()
    req.cookies = parseCookies req

    # Gets token from header in CORS
    if req.headers and req.headers.vtexidclientautcookie
      req.cookies.VtexIdclientAutCookie = req.headers.vtexidclientautcookie

    logger.logCookies(req.cookies)

    # Redirects to login page if user does not have vtex id cookie
    if not req.cookies.VtexIdclientAutCookie
      logger.logCookieNotFound()
      return redirect res, redirectSettings.redirectUrl

    # Checks if vtex id auth info is already cached
    logger.logCacheCheck()
    cache.get req.cookies.VtexIdclientAutCookie, (err, value) ->
      return next(err) if err

      if value[req.cookies.VtexIdclientAutCookie]
        vtexIdData = value[req.cookies.VtexIdclientAutCookie]
        logger.logCachedUser(vtexIdData.user)

        req.vtex.vtexIdData = vtexIdData
        req.vtex.vtexIdData.fromCache = true

        return next()
      else
        logger.logApiRequest()
        vtexIdEndpoint = "https://vtexid.vtex.com.br/api/vtexid/pub/authenticated/user?authToken="
        urlEncodedAuthCookie = encodeURIComponent(req.cookies.VtexIdclientAutCookie)
        return request.get (vtexIdEndpoint + urlEncodedAuthCookie), (err, response, body) ->
          unless body? and body.length > 0
            logger.logRedirectToLoginPage()
            return redirect(res, options.logoutUrl, req.url)

          try
            body = JSON.parse(body)

            logger.logApiResponseCode(response.statusCode)

            unless body?
              logger.logRedirectToLoginPage()
              return redirect(res, options.logoutUrl, req.url)
            if body.error
              logger.logRedirectToLoginPage()
              return redirect(res, options.logoutUrl, req.url)
            unless body.user?
              logger.logUnauthorizedUser()
              return unauthorized(body)

            logger.logCachingUser(body.user)
            cache.set req.cookies.VtexIdclientAutCookie, body

            req.vtex.vtexIdData = body
            req.vtex.vtexIdData.fromCache = false

            next()
          catch e
            return next(e)

module.exports = authenticationHandler
