const debug = require('debug')('ctrl:common');
const util = require('util');
const url = require('url');
const sso = require('src/utils/sso/index.js');
const redis = require('src/utils/redis.js');
const { codeMessage, APIError } = require('src/utils/response/index.js');
const config = require('src/config/index.js');
const { jwt } = require('src/utils/pkgs.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 = redis.Key.ssoLoginCache(state);

  const data = await redis.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);

    // generate jwt token
    const jwtToken = jwt.sign(
      {
        user_id: `${token}-id`,
        sso: true,
      },
      config.server.jwt_secret,
      {
        expiresIn: config.server.jwt_expire,
        issuer: 'lawsnote',
      }
    );

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

    try {
      await redis.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());
};
