const jwt = require('jsonwebtoken')
const router = require('express').Router()
const { ok, fail } = require('../lib/response')
const { signUser, readBearer } = require('../lib/auth')
const { code2Session } = require('../lib/wechat')
const { getSettings } = require('../lib/settings-cache')
const config = require('../config')
const userDao = require('../dao/user.dao')
const logDao = require('../dao/log.dao')

const wrap = fn => (req, res, next) => fn(req, res, next).catch(next)

router.post('/auth/login', wrap(async (req, res) => {
  const settings = await getSettings()
  if (settings.maintenance_mode === true) return res.json(fail(2001, '系统维护中，请稍后再试'))

  const session = await code2Session(req.body.code || '')
  let user = await userDao.findByOpenid(session.openid)
  let isNewUser = false
  if (!user) {
    isNewUser = true
    const result = await userDao.create(session.openid)
    user = await userDao.findById(result.insertId)
    await logDao.write({ user_id: user.user_id, action: 'user_register', detail: '新用户注册', ip: req.ip })
  }
  const token = signUser(user)
  await logDao.write({ user_id: user.user_id, action: 'user_login', detail: '用户登录', ip: req.ip })
  res.json(ok({
    token,
    user_id: String(user.user_id),
    is_new_user: isNewUser,
    user_info: {
      user_id: String(user.user_id),
      nickname: user.nickname || '用户' + String(user.user_id),
      avatar: user.avatar || '',
      phone: user.phone || '',
      gender: user.gender || 0
    },
    expires_in: 604800
  }))
}))

router.post('/auth/refresh', wrap(async (req, res) => {
  const token = readBearer(req.headers)
  if (!token) return res.json(fail(1001, 'token_expired'))

  let payload
  try {
    payload = jwt.verify(token, config.jwt.secret)
  } catch (err) {
    if (err.name === 'TokenExpiredError') {
      try {
        payload = jwt.verify(token, config.jwt.secret, { ignoreExpiration: true })
      } catch (_) {
        return res.json(fail(1001, 'token_expired'))
      }
      const now = Math.floor(Date.now() / 1000)
      const gracePeriod = 1 * 24 * 60 * 60 // 1 day
      if (now - payload.exp > gracePeriod) {
        return res.json(fail(1001, 'token_expired'))
      }
    } else {
      return res.json(fail(1001, 'token_expired'))
    }
  }

  if (payload.type !== 'user') return res.json(fail(1001, 'token_expired'))

  const now = Math.floor(Date.now() / 1000)
  const sevenDays = 7 * 24 * 60 * 60
  if (payload.exp && payload.exp > now && (payload.exp - now) > sevenDays) {
    return res.json(ok({ token, expires_in: payload.exp - now }))
  }

  const user = await userDao.findById(payload.user_id)
  if (!user) return res.json(fail(1001, 'token_expired'))

  const newToken = signUser(user)
  res.json(ok({ token: newToken, expires_in: 604800 }))
}))

module.exports = router
