sessions = {}
staffs = {}

request = require('request')
Promise = require('bluebird')
chance = new require('chance')()
_ = require('lodash')

config = require('../config')
log = require('../log')
errors = require('../errors')

mongoStore = require('../mongoStore')

pRequest = Promise.promisify(request)
pRestPost = (url, body)-> pRequest url: url, method: 'POST', json: body
pRestGet = (url, query)-> pRequest url: url, method: 'GET', qs: query

gCollectionSession = ->
    db = yield mongoStore.db()
    db.collection 'session'

gCollectionStaff = ->
    db = yield mongoStore.db()
    db.collection 'staff'

gLoadSession = (accountId)->
    c = yield from gCollectionSession()
    session = yield mongoStore.findOne.call c, {_id: accountId?.toString()}
    return session

gPersistSession = (session)->
    c = yield from gCollectionSession()
    yield mongoStore.updateOne.call c, {_id: session._id.toString()}, session, {upsert: true}
    return true

gClearSession = (id)->
    c = yield from gCollectionSession()
    yield mongoStore.deleteOne.call c, {_id: id}
    return true

buildAccountRequestUrl = (path)->
    url = config.account.server + "internal/#{path}?authName=#{config.account.clientName}&authKey=#{config.account.clientKey}"
    # log.system.debug url
    url

gAuthUserFromAccountCenter = (username, password)->
    res = yield pRestPost(buildAccountRequestUrl('auth'), {username, password})

    if res.statusCode == 200
        return res.body
    else if res.statusCode == 400
        throw new errors.UserError(res.body?.code, res.body?.message)
    else
        log.system "signIn exception", status: res.statusCode
        throw new errors.SystemError("AccountCenterInternalError", res.statusCode)

# 根据用户的手机或邮箱构造一个用户名
buildIdName = (phone, email)->
    if phone
        phone[0...3] + "****" + phone[7...]
    else if email
        /^(.+)@/.exec(email)?[1]
    else
        ''

gGetOrLoadSession = (id)->
    session = sessions[id]
    return session if session

    session = yield from gLoadSession(id)
    sessions[id] = session if session?
    return session
exports.gGetOrLoadSession = gGetOrLoadSession

# 向用户系统，根据邮箱或手机查询用户
exports.gGetUserByContact = (phoneOrEmail) ->
    res = yield pRestGet(buildAccountRequestUrl('user-by-contact'), {phoneOrEmail})

    if res.statusCode == 200
        return JSON.parse(res.body)
    else if res.statusCode == 404
        return null
    else if res.statusCode == 400
        throw new errors.UserError(res.body?.code, res.body?.message)
    else
        log.system.error "gGetUserByContact exception", status: res.statusCode
        throw new errors.SystemError("AccountCenterInternalError", res.statusCode)

# 登录
exports.gSignIn = (username, password, staffRequired) ->
    auth = yield from gAuthUserFromAccountCenter username, password
    auth.username = username
    auth.idName = buildIdName(auth.phone, auth.email)

    staff = staffs[auth._id]
    throw new errors.UserError('StaffRequired') if staffRequired and not staff?

    if staff?
        auth.isStaff = true
        auth.truename = staff.truename
        auth.permissions = staff.permissions

    # 生成token
    auth.token = chance.string(length: 20)
    auth.sessionExpireAt = Date.now() + config.sessionExpireAtServer

    sessions[auth._id] = auth
    yield from gPersistSession auth

    return auth

exports.gAddStaff = (userId, truename, createdBy)->
    createdOn = new Date()
    createdBy = mongoStore.stringToObjectId(createdBy)
    c = yield from gCollectionStaff()
    try
        staff = {_id: userId, truename, createdBy, createdOn, permissions: []}
        yield mongoStore.insertOne.call c, staff
        staffs[userId] = staff
        log.system.debug staff
    catch e
        throw new errors.UserError('UserIsStaffAlready') if mongoStore.isIndexConflictError e
        throw e

# 身份验证，校验id和token
exports.gAuthenticate = (accountId, token)->
    session = yield gGetOrLoadSession accountId
    return false unless session

    if session.token != token
        return false
    if Date.now() > session.sessionExpireAt
        return false
    session.sessionExpireAt = Date.now() + config.sessionExpireAtServer # 展期
    return session

# 登出
exports.gSignOut = (userId)->
    delete sessions[userId]
    yield from gClearSession userId
    return true

# 清除相关用户记录
exports.gClearAccountCache = (ids)->
    log.system.info 'clear user cache', ids
    for id in ids
        delete sessions[id]
        yield from gClearSession id

exports.listStaff = -> _.values(staffs)

exports.gUpdatePermissions = (staffId, permissions)->
    c = yield from gCollectionStaff()
    yield mongoStore.updateOne.call c, {_id: staffId}, {$set: {permissions: permissions}}

    session = yield from gGetOrLoadSession(staffId)
    if session # 可能尚未登录
        session.permissions = permissions
        yield from gPersistSession(session)

    staffs[staffId].permissions = permissions

# 加载到缓存
exports.gLoadStaffs = ->
    c = yield from gCollectionStaff()
    cursor = c.find({})
    staffList = yield mongoStore.toArray.call cursor

    staffs[s._id] = s for s in staffList

exports.getStaffById = (id)-> staffs[id]






