const { Consola } = require("consola");
const { cleanDoubleSlashes, normalizeURL } = require("ufo");
const replaceAll = require("fast-replaceall");
const jwt = require('jsonwebtoken');
const fs = require('fs');
const bcrypt = require('bcrypt');
const _ = require("lodash");
const { omit } = require("lodash");
const { resolve } = require("path");

function cleanURL(url) {
  return normalizeURL(cleanDoubleSlashes(url));
}

function restartServer(){
 var pidFile =cleanPath(process.cwd()+'/.tmp/.pid')
 try{
  var data = fs.readFileSync(pidFile,'utf-8')
  if(data=='restart')  {
    fs.writeFileSync(pidFile,'0',()=>{})
   
  }
 } catch(err){

 }

}

function formatError(err) {
  let mxg = err + "";

  if (err.code) {
    // The .code property can be accessed in a type-safe manner
    if (err.code === "P2002") {
      mxg = `There is a unique constraint violation  ${
        err?.meta?.target || ""
      } `;
    }
  }

  if (err.message?.match(/(Argument where is missing.)/)) {
    mxg = "Argument where is missing.";
  }

  if (err.message?.match(/(Argument data is missing.)/)) {
    mxg = "Argument data is missing.";
  }

  var directory = __dirname;
  var toString = mxg || err.message + "";
  toString = replaceAll(toString, process.env.DATABASE_URL, "");
  toString = replaceAll(toString, directory, "");
  toString = replaceAll(toString, "prisma", "");

  return toString;
}

async function encryptPassword(password) {
  
}

async function publicOrPrivateApi(p = [], req) {
  var method = req.method + "";
  method = method.toLowerCase();
  var model = req.params.model?.toLowerCase() || null;
  var _conf_ = {
    model: model,
    public: false,
    middlewares: [],
  };

  return new Promise(async (resolve, reject) => {
    for await (access of p) {
      let _api_ = access.split("::"); // Array of element
      let _model_ = _api_[0] || null;
      let _method_ = _api_[1] || null;
      let _permission_ = _api_[2] || "private";
      let _middleware_ = _api_[3]?.split("|") || [];

      if (_model_ == model && method == _method_) {
        _conf_.public = _permission_ == "public" ? true : false;
        _conf_.middlewares = _middleware_;
      } else {
      }
    }

    resolve(_conf_);
  });
}

function cleanPath(link) {
  let Path = link.replace(/\\/g, "/");
  Path = Path.replace("/node_modules/@bitev.io/core", "");

  return Path;
}

async function privateFields(model, docs, config, method) {
  return new Promise(async (resolve, reject) => {
    model = model.toLowerCase();
    if (config?.modelProviders[model]?.privateFields?.length) {
      var privateFields = config?.modelProviders[model]?.privateFields || [];

      if (method == "MANY") {
        var docs_ = [];
        for await (doc of docs) {
          docs_.push(_.omit(doc, privateFields));
        }
        return resolve(docs_);
      }

      if (method == "SINGLE") {
        return resolve(_.omit(docs, privateFields));
      }
    } else {
      return resolve(docs);
    }
  });
}


function getJwt(token=''){

  try{
  var valueOf = token.match(/^AUTHSSID\=(.*)/)[1] || token.tolowercase().match(/^JWT\=(.*)/)[1] || null
  return valueOf
  } catch(err){
    return null
  }

}


function verifyToken(token,config) {
  return new Promise(function(resolve, reject) {
    try{
    var decoded= jwt.verify(token, config.jwt_key)
    resolve(decoded)
    } catch(err){
      console.log(err)
     reject(err)
    }
 
  })
 
 }

 function toLowerCase(model){
  if(model) return model?.toLowerCase()
  return model
 }


function createRootFolder(repoName){
 return new Promise((resolve,reject)=>{
  const folders_extensions =['endpoints','plugins','services','tasks','api']
  const root_folders = ['admin','uploads']
    folders_extensions.map(folder=>{
     let dir = process.cwd()+'/extensions/'+folder
       if(fs.existsSync(dir)){
       } else {
        fs.mkdirSync(dir)
       }
    })
    // root folders
    root_folders.map(folder=>{
        let dir = process.cwd()+'/'+folder
          if(fs.existsSync(dir)){
          } else {
           fs.mkdirSync(dir)
           
          }
       })
       resolve()
 })

}


function imageToBase64(filePath,options={
  usePrefix:false,
  mimeType:null
}){

  const img = fs.readFileSync(filePath)
  var base64String = Buffer.from(img).toString("base64")

  if(options.usePrefix){
    base64String = `data:${options.mimeType};base64,` + base64String;
  }
  return base64String
}

async function hashPassword(plaintextPassword) {
  const hash = await bcrypt.hash(plaintextPassword, 10);
  return hash
  // Store hash in the database
}

// compare password
async function comparePassword(plaintextPassword, hash) {
  const result = await bcrypt.compare(plaintextPassword, hash);
  return result;
}

function isAlreadyHashed(hash){
  try{
    bcrypt.getRounds(hash)
    return true
   } catch(err){
     return false
   }
}

async function deepDivePassword(data={}){
 return new Promise(async(resolve, reject) => {  
  for await(var key of Object.keys(data)){
    var isObject =  typeof data[key] === "object" || typeof data[key] === "array" ? true:false
    if(isObject)  await deepDivePassword(data[key])
    if(key=='password'){
      try{
       bcrypt.getRounds(data[key])
      } catch(err){
        // If not already hashed in the database
        data[key] = await hashPassword(data[key]);
      }
    }
  }
  return resolve(data)
 })
}

module.exports = {
  formatError,
  cleanURL,
  encryptPassword,
  publicOrPrivateApi,
  cleanPath,
  privateFields,
  getJwt,
  verifyToken,
  toLowerCase,
  restartServer,
  createRootFolder,
  imageToBase64,
  hashPassword,
  comparePassword,
  deepDivePassword,
  isAlreadyHashed
};
