###
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'
base64 = require '../libs/base64'

migratedAccounts = ["iam"]

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?
  options.migrationEndPoint or= 'https://accounts.vtex.com/index.html#/'

  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

    # 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)

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

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

      if req.headers.originalHost?
        referer = req.vtex.store + ".vtexlocal.com.br"
      else
        referer = req.headers.host

      refererRegexp = /([a-zA-Z0-9-$_.+]*)/
      match = refererRegexp.exec(referer)
      domain = match[1]

      expiredDate = new Date()
      expiredDate.setYear(2000)
      expiredCookieName = "VtexIdclientAutCookie="
      expiredDomain = "domain=#{domain}"
      expiredDottedDomain = "domain=.#{domain}"
      expiredDate = "expires=#{expiredDate.toUTCString()}"
      expiredPath = "path=/"
      expired = "#{expiredCookieName}; #{expiredDomain}; #{expiredDate}; #{expiredPath}"
      expiredDotted = "#{expiredCookieName}; #{expiredDottedDomain}; #{expiredDate}; #{expiredPath}"
      expiredWithoutDomain = "#{expiredCookieName}; #{expiredDate}; #{expiredPath}"
      res.setHeader('Set-Cookie', expiredWithoutDomain)
      res.setHeader('Set-Cookie', expiredDotted)
      res.setHeader('Set-Cookie', expired)

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

    # 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()
      if (req.vtex.store && (req.vtex.store in migratedAccounts))
        if req.query.ott
          return next()

        fullUrl = 'https://' + req.host + req.originalUrl;
        redirectUri = base64.encode fullUrl
        redirectUrl = options.migrationEndPoint + req.vtex.store + "/?redirectUri=" + redirectUri
      else
        redirectUrl = redirectSettings.redirectUrl

      return redirect res, 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
