const fs = require("fs");
const path = require("path");
const jwt = require("jsonwebtoken");
const randtoken = require("rand-token");
const bCrypt = require("bcrypt");
const config = require("../config");

const privateKEY = fs.readFileSync(path.join(__dirname, "..", "private.key"), "utf8");
const publicKEY = fs.readFileSync(path.join(__dirname, "..", "public.key"), "utf8");

const signOptions = {
  issuer: "Fundación LQDVI",
  subject: "info@loquedeverdadimporta.org",
  audience: "htts://www.loquedeverdadimporta.org",
};

const _genSalt = (rounds = 10) => {
  return new Promise((resolve, reject) => {
    bCrypt.genSalt(rounds, function (err, salt) {
      if (err) return reject(err);
      return resolve(salt);
    });
  });
};

const _hashPassword = (password, salt) => {
  return new Promise((resolve, reject) => {
    bCrypt.hash(password, salt, function (err, hash) {
      if (err) return reject(err);
      return resolve(hash);
    });
  });
};

// https://medium.com/@siddharthac6/json-web-token-jwt-the-right-way-of-implementing-with-node-js-65b8915d550e

const _sign = (payload, options) => {
  /*
    options = {
        issuer: "Authorizaxtion/Resource/This server",
        subject: "iam@user.me",
        audience: "Client_Identity" // this should be provided by client
    }
    */

  // Token signing options
  const signOptions = {
    issuer: options.issuer,
    subject: options.subject,
    audience: options.audience,
    expiresIn: config.session.token_expires_in,
    algorithm: "RS256",
  };

  const token = jwt.sign(payload, privateKEY, signOptions);
  const refreshToken = randtoken.uid(256);
  refreshToken[refreshToken] = payload;
  return { token, refreshToken };
};

const _verify = (token, options) => {
  /*
    options = {
        issuer: "Authorization/Resource/This server",
        subject: "iam@user.me", 
        audience: "Client_Identity" // this should be provided by client
    }  
    */

  const verifyOptions = {
    issuer: options.issuer,
    subject: options.subject,
    audience: options.audience,
    expiresIn: config.session.token_expires_in,
    algorithm: ["RS256"],
  };

  //console.log('_VERIFY - SECURiTY.HELPERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR');
  //console.log('token: ', token);
  //console.log('publicKEY: ', publicKEY);
  //console.log('verifyOptions: ', verifyOptions);

  try {
    return jwt.verify(token, publicKEY, verifyOptions);
  } catch (err) {
    return false;
  }
};

const _decode = (token) => {
  //returns null if token is invalid
  return jwt.decode(token, { complete: true });
};

module.exports = {
  jwtOptions: {
    jwtFromRequest: (req) => {
      console.log(req.headers);
      return req && req.headers && req.headers["x-access-token"] ? req.headers["x-access-token"] : null;
    },
    secretOrKey: publicKEY,
    ...signOptions,
  },

  generateHashPassword: async (password) => {
    const salt = await _genSalt();
    return _hashPassword(password, salt);
  },

  isValidPassword: async (password, candidate) => {
    return await bCrypt.compareSync(candidate, password);
  },

  generateToken: (payload) => {
    return _sign(payload, signOptions);
  },

  verify: (tokenOrKey) => {
    if (tokenOrKey === config.server.api_key) {
      return true;
    } else {
      return _verify(tokenOrKey, signOptions);
    }
  },
};
