const debug = require('debug')('ctrl:common')
const util = require('util')
const url = require('url')
const sso = require('src/utils/sso/index.js')
const { get: getCacheInstance } = require('src/utils/cache.js')
const { resp, codeMessage, APIError } = require('src/utils/response/index.js')
const config = require('src/config/index.js')
const acl = require('src/utils/acl.js')
const { copyObject } = require('src/utils/index.js')

const controller = {}
module.exports = controller

controller.verifyCode = () => async (ctx) => {
  const { code, session_state: sessionState, state } = ctx.query

  // logout flow redirect tot frontend
  if (state === 'logout') {
    ctx.redirect(config.server.frontend_url)
    return
  }

  // get back url from redis
  const cacheKey = `login-${state}`
  const cache = getCacheInstance()

  const data = cache.get(cacheKey)
  if (!data) ctx.throw('get login cache fail')
  const stateObj = JSON.parse(data)
  const { back_url: backURL } = stateObj
  if (!backURL) ctx.throw('cache data missing')

  const u = new url.URL(backURL)

  try {
    const token = await sso.getToken(code, sessionState)

    if (!acl.checkAllow(token.groups)) {
      const copy = copyObject(resp.Forbidden)
      copy.object = codeMessage.CodeAccountNoPermission
      throw new APIError('account no permission', copy)
    }

    // set accessToken/refreshToken cache
    cache.set(token.access_token, token.refresh_token, false)

    u.searchParams.append(
      'success',
      Buffer.from(JSON.stringify({ token: token.access_token })).toString('base64')
    )

    try {
      cache.del(cacheKey)
    } catch (err) {
      debug(`delete cache fail: ${util.inspect(err, false, null)}`)
    }
  } catch (err) {
    debug(`openid verify fail: ${util.inspect(err, false, null)}`)

    /** @type {object} */
    const errObj = { ...codeMessage.CodeInternalError }

    if (err instanceof APIError) {
      // @ts-ignore
      Object.assign(errObj, err.object.object)
    }

    errObj.errorStack = err.stack
    errObj.errorMessage = err.message
    u.searchParams.append(
      'error',
      Buffer.from(JSON.stringify(errObj)).toString('base64')
    )
  }

  ctx.redirect(u.toString())
}
