{_} = require 'underscore'

crypto = require('crypto')
querystring = require('querystring');
Cookies = require( "cookies" )


request = require 'request'
authHeaders = {AUTHUSER: process.env.AUTHUSER, AUTHTOKEN: process.env.AUTHTOKEN}
request = request.defaults(json: true, headers: authHeaders, timeout: 30 * 1000)

config = require './config'
redis = require './redis'

USER_KEY = "users"
AUTH_KEY = "auth"
BANS_KEY = "bans"
MUTE_KEY = "mute"

return_sso_url="http://91.121.152.74:8000/"
secretstring = config.SECRET_KEY
loggedin = false

# This middleware checks if a user is authenticated through the site. If yes,
# then information about the user is stored in req.user. In addition, we store
# a token associated with that user into req.user.token.
#
# User information is also stored in redis.
exports.middleware = -> (req, res, next) ->
  cookies = new Cookies( req, res )

  return next()  if req.path.match(/^\/css|^\/js|^\/fonts|^\/Sprites|^\/replays\/\b/)
  return next()  if req.path.match(/^\/leaderboard/)  # add some proper site authentication later instead

  authenticate req, (body) ->
    if !loggedin
      if req.query.sso
        sso = req.query.sso
        sig = req.query.sig
        cryptedret = crypto.createHmac('SHA256', secretstring).update(sso).digest('hex')
        if cryptedret != sig
           return
        else
           base64decode = new Buffer(sso, 'base64').toString('ascii')
           userobject = querystring.parse(base64decode)
           nonce = cookies.get("nonce")
           noncereturn = userobject.nonce
           if noncereturn != nonce
              return
           else
              setdatabasedata(req, cookies, userobject, next)
      else
        parameters = getparameters(req)
        nonce = new Date().getTime() + '' + new Date().getMilliseconds(); 
        cookies.set("nonce", nonce)
        return_sso_url="http://91.121.152.74:8000" + req.url
        payload = "nonce=" + nonce + "&return_sso_url=" + return_sso_url
        base64payload = new Buffer(payload).toString('base64')
        urlencoded = encodeURIComponent(base64payload)
        crypted = crypto.createHmac('SHA256', secretstring).update(base64payload).digest('hex')
        return res.redirect("http://91.121.152.74/session/sso_provider?sso=" + urlencoded + "&sig=" + crypted)

exports.matchToken = (req, id, token, next) ->
  hmac = crypto.createHmac('sha256', config.SECRET_KEY)
  rawcookies = req.headers.cookie
  rawcookiesarr = rawcookies.split('; ')
  noncearr = rawcookiesarr.filter (x) -> x.substring(0, 6) == "nonce="

  if (noncearr[0])
    noncecookie = noncearr[0].replace("nonce=", "")
  
  if token != noncecookie
    return next(new Error("Invalid session!"))
  redis.shard 'hget', USER_KEY, id, (err, jsonString) ->
    if err then return next(err)
    json = JSON.parse(jsonString)
    return next(new Error("Invalid session!"))  if !json
    exports.getAuth json.name, (err, authLevel) ->
      if err then return next(err)
      json.authority = authLevel
      return next(null, json)

setdatabasedata = (req, cookies, object, next) ->
   username = object.username
   id = object.external_id
   admin = object.admin
   mod = object.moderator
   req.user = {}
   req.user.token = cookies.get("nonce")
   req.user.id = id
   req.user.name = username
   if username == "Deukhoofd" && admin == "true"
     exports.setAuth username, exports.levels.OWNER
   else if admin == "true"
     exports.setAuth username, exports.levels.ADMIN
   else if mod == "true"
     exports.setAuth username, exports.levels.MOD
   else
     exports.setAuth username, exports.levels.USER
   toJSON = {
      name : username,
      token : cookies.get("nonce")
      id : id
   }
   redis.shard('hset', USER_KEY, id, JSON.stringify(toJSON), next)


authenticate = (req, next) ->
  return next()


getparameters = (req) ->
    return("1")


generateUsername = (req) ->
  name = req.param('user')
  return name  if name
  {SpeciesData} = require './xy/data'
  randomName = (name  for name of SpeciesData)
  randomName = randomName[Math.floor(Math.random() * randomName.length)]
  randomName = randomName.split(/\s+/)[0]
  randomName += "Fan" + Math.floor(Math.random() * 10000)
  randomName

generateId = (req) ->
  req.param('id') || Math.floor(1000000 * Math.random())

generateUser = (req) ->
  {id: generateId(req), username: generateUsername(req)}

# Authorization

exports.levels =
  USER          : 1
  DRIVER        : 2
  MOD           : 3
  MODERATOR     : 3
  ADMIN         : 4
  ADMINISTRATOR : 4
  OWNER         : 5

LEVEL_VALUES = (value  for key, value of exports.levels)

exports.getAuth = (id, next) ->
  id = String(id).toLowerCase()
  redis.hget AUTH_KEY, id, (err, auth) ->
    if err then return next(err)
    auth = parseInt(auth, 10) || exports.levels.USER
    next(null, auth)

exports.setAuth = (id, newAuthLevel, next) ->
  id = String(id).toLowerCase()
  if newAuthLevel not in LEVEL_VALUES
    next(new Error("Incorrect auth level: #{newAuthLevel}"))
  redis.hset(AUTH_KEY, id, newAuthLevel, next)

# Ban
# Length is in seconds.
exports.ban = (id, reason, length, next) ->
  id = id.toLowerCase()
  key = "#{BANS_KEY}:#{id}"
  if length > 0
    redis.setex(key, length, reason, next)
  else
    redis.set(key, reason, next)

exports.unban = (id, next) ->
  id = String(id).toLowerCase()
  redis.del("#{BANS_KEY}:#{id}", next)

exports.getBanReason = (id, next) ->
  id = String(id).toLowerCase()
  redis.get("#{BANS_KEY}:#{id}", next)

exports.getBanTTL = (id, next) ->
  id = String(id).toLowerCase()
  key = "#{BANS_KEY}:#{id}"
  redis.exists key, (err, result) ->
    if !result
      # In older versions of Redis, TTL returns -1 if key doesn't exist.
      return next(null, -2)
    else
      redis.ttl(key, next)

# Mute
# Length is in seconds.
exports.mute = (id, reason, length, next) ->
  id = String(id).toLowerCase()
  key = "#{MUTE_KEY}:#{id}"
  if length > 0
    redis.setex(key, length, reason, next)
  else
    redis.set(key, reason, next)

exports.unmute = (id, next) ->
  id = String(id).toLowerCase()
  key = "#{MUTE_KEY}:#{id}"
  redis.del(key, next)

exports.getMuteTTL = (id, next) ->
  id = String(id).toLowerCase()
  key = "#{MUTE_KEY}:#{id}"
  redis.exists key, (err, result) ->
    if !result
      # In older versions of Redis, TTL returns -1 if key doesn't exist.
      return next(null, -2)
    else
      redis.ttl(key, next)
