import * as express from 'express';
import * as querystring from 'querystring';
import axios from 'axios';
import * as crypto from 'crypto';

const AUTH_REDIRECT_URI = '/audkenning/callback';
const AUTH_CLIENT_ID = 'portal_www';
const AUTH_SCOPE = 'openid nova_graphql';
const AUTH_RESPONSE_TYPE = 'id_token code';
const AUTH_GRANT_TYPE = 'authorization_code';
const AUTH_RESPONE_MODE = 'form_post';

function getProtocol(req: any) {
  const proto = req.get('host') === 'localhost:4000' ? 'http' : 'https';

  return proto;
}

const getToken = async (code: string, redirect_uri: string) => {

  const tokenParams = {
    client_id: AUTH_CLIENT_ID,
    grant_type: AUTH_GRANT_TYPE,
    scope: AUTH_SCOPE,
    code,
    redirect_uri,
  };

  try {
    const res = await axios.post(`${process.env.AUTHENTICATION_SERVER_URL}/connect/token`,
      querystring.stringify(tokenParams), {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
      });

    if (res && res.data.access_token) {
      return res.data.access_token;
    }
  } catch (e) {
    console.error('Exception getting token: ', e); // TODO: improve error handling
  }

  return undefined;
};

const authentication = express.Router();

authentication.post('/callback', async (req, res) => {
  // TODO(halldor): verify that the received state (from req) mathces the one we generated in the /begin action
  const token = await getToken(req.body.code, `${getProtocol(req)}://${req.get('host')}${AUTH_REDIRECT_URI}`);

  if (token) {
    res.cookie('token', token, { sameSite: 'none', secure: true });

    const inital_redirect_uri = Buffer.from(req.body.state, 'base64').toString();

    return res.redirect(inital_redirect_uri || '/');
  }

  return res.status(401).send('Authentication failed');
});

authentication.get('/begin', (req: any, res) => {
  // TODO(halldor): we should keep track of state/nonce
  const params: any = {
    client_id: AUTH_CLIENT_ID,
    scope: AUTH_SCOPE,
    nonce: crypto.randomBytes(8).toString('hex'),
    response_type: AUTH_RESPONSE_TYPE,
    response_mode: AUTH_RESPONE_MODE,
    state: Buffer.from(req.query.redirect_uri).toString('base64'),
    redirect_uri: `${getProtocol(req)}://${req.get('host')}${AUTH_REDIRECT_URI}`,
    // acr_values: 'idp:nova_adfs',
  };

  if (req.query.acr === 'adfs') {
    params.acr_values = 'idp:nova_adfs';
  }

  if (req.query.prompt === 'login') {
    params.prompt = 'login';
  }

  const authorizeUrl = `${process.env.AUTHENTICATION_SERVER_URL}/connect/authorize?${querystring.stringify(params)}`;

  return res.redirect(authorizeUrl);
});

export default authentication;
