const { argv } = require('process');
const fs = require("fs-extra");
const path = require("path");
const dnsSync = require("dns-sync");
const mustache = require("mustache");
const readlineSync = require("readline-sync");

const Wwws = require("../models/Wwws.js");
const Nations = require("../models/Nations.js");
/**
 * This Setup is run at the first installation
 * This is not an exportable module
 *
 *
 *
 */

const Setup = {};
//const nationsync = require('./Nations').updateChains();

Setup.check = (param) => {
  //run a nationchains sync nd check town does not already exist
  ["nationId","townId","url"].forEach(k=>{
    if (!param[k]){
      console.log(`Please provide a ${k} in your param`)
      process.exit();
    }
  })
  const initconf = fs.readJsonSync('./adminapi/www/adminapx/tpldata/initconf.json')
  let nationupdated=false;
  for (let t=0; t<initconf.towns;t++){
    const synchro = Nations.synchronize(initconf.towns[t].url)   
    if (synchro.status==200){
      nationupdated=true;
      break;} 
  }
  if (!nationupdated){
    Console.log('Please check your internet access other towns cannot be reach to synchronize your town')
    process.exit();
  }
  // check nationId exist and townId not
  if (!Object.keys(fs.readJsonSync('../../nationchains/nations/idx/nationId_all.json')).includes(param.nationId) {
     console.log(`Sorry your nationId: ${param.nationId} does not exist`);
     process.exit();
    }
  if (Object.keys(fs.readJsonSync('../../nationchains/towns/idx/townId_all.json')).includes(param.townId) {
    console.log(`Sorry your townId: ${param.townId} already exist, please choose another one`);
    process.exit();
 }
  if ("testinternet" != "testinternet") {
    console.log(
      "\x1b[31m Check your internet access, to setup this town we need to update the Nations. It seems we cannot do it"
    );
    process.exit();
  }
  if (!fs.existsSync("/etc/nginx/nginx.conf")) {
    console.log(
      "\x1b[31m Check documentation, nginx have to be installed on this server first, no /etc/nginx/nginx.conf available"
    );
    process.exit();
  }
  if (fs.existsSync("./adminapi/www/nginx_adminapx.conf")) {
    console.log(
      "\x1b[31m Be carefull you already have a town set, check http://adminapx or remove ./adminapi/www/nginx_adminapx.conf to reset nginxconf"
    );
    process.exit();
  }
  return true;
};

Setup.init = async (param) => {
  /**
   *  create empty nationchains
   *  rsync all subfolder nationchains except the tribes/ and /www/nginx_adminapx.conf
   *
   *  Then to send new version we fix a master production
   *
   */
  const initconf = fs.readJsonSync('./adminapi/www/adminapx/tpldata/initconf.json')

  initconf.sudoerUser = process.env.USER;
  initconf.dirapi = path.resolve(`${__dirname}/../../`);
  initconf.dirtown = path.resolve(`${__dirname}/../../../${param.townId}-${param.nationId}/`)
  // To allow to serve the nation website until the end
  initconf.nginx.include.push(
    `${initconf.dirapi}/adminapi/www/nginx_*.conf`
  );
  // To allow to serve tribes web site
  initconf.nginx.include.push(
    `${initconf.dirtown}/tribes/*/www/nginx_*.conf`
  );
  initconf.dns.push(param.url)
  initconf.nginx.logs = `${dirtown}/logs/nginx/adminapx`;
  initconf.nginx.website = "adminapx";
  initconf.nginx.fswww = `${dirapi}/adminapi/www`;
  initconf.nginx.pageindex = "index_en.html";
  const nginxconf = fs.readFileSync(
    "../../adminapi/www/adminapx/static/tpl/nginx.conf.mustache",
    "utf8"
  );
  const proxyparams = fs.readFileSync(
    "../../adminapi/www/adminapx/static/tpl/nginxproxy_params.mustache",
    "utf8"
  );
  // saved and change nginx conf
  if (!fs.existsSync("/etc/nginx/nginxconf.saved")) {
    fs.moveSync("/etc/nginx/nginx.conf", "/etc/nginx/nginxconf.saved");
    console.log(
      "your previous /etc/nginx/nginx.conf was backup in  /etc/nginx/nginxconf.saved"
    );
  }
  fs.outputFileSync(
    "/etc/nginx/nginx.conf",
    mustache.render(nginxconf, initconf),
    "utf8"
  );
  fs.outputFileSync(
    "/etc/nginx/proxy_params",
    mustache.render(proxyparams, initconf),
    "utf8"
  );
  if (!fs.existsSync(initconf.nginx.logs)) fs.mkdirSync(initconf.nginx.logs);
  const { exec } = require("child_process");
  exec(.restart, (error, stdout, stderr) => {
    if (error) {
           console.log("\x1b[42m", error, stdout, stderr, "x1b[0m");
          //@todo supprimer la derniere config et relancer
    } else {
        console.log(
          `\x1b[42m###########################################################################################\x1b[0m\n\x1b[42mWellcome into apxtrib, you can now 'yarn dev' for dev or 'yarn startpm2' for prod or       \n'yarn unittest' for testing purpose. Access to your town here \x1b[0m\x1b[32mhttp://${param.url}\x1b[0m \x1b[42m             \nto finish your town setup. Don't forget to set your localhost /etc/hosts by adding 127.0.0.1 adminapx or {LAN IP} adminapx .  Check README's project to learn more.                          \x1b[0m\n\x1b[42m###########################################################################################\x1b[0m`
        );
    }
};

if (argv.length!=5) {
  console.log("Check you parameter you need to type yarn setup nationId:ants townid:mytown url:mytown-ants ")
  process.exit()
}
const param={};
argv.slice(2).forEach(arg=>{
  const kv=arg.split(':')
     if (kv.length==2){
        param[kv[0]]=kv[1]
     }else{
        console.log('Check your args that have to be yarn main key1:val1 keyn:valn');
        process.exit(1);
     }
})
if (Setup.check(param)) Setup.init(param);

// After testing remove all stuff after this line

Setup.initold = async () => {
  // Get standard conf and current data
  const townconf = fs.readJsonSync("./nationchains/www/adminapx/townconf.json");
  const apxnations = fs.readJsonSync(
    `./nationchains/nations/idx/nationId_all.json`
  );
  const apxtowns = fs.readJsonSync(`./nationchains/towns/idx/townId_all.json`);

  let apxpagans = {};
  if (fs.existsSync(`./nationchains/pagans/idx/alias_all.json`)) {
    apxpagans = fs.readJsonSync(`./nationchains/pagans/idx/alias_all.json`);
  }

  if (!Object.keys(apxnations).includes(townconf.nationId)) {
    console.log(
      `Sorry nationId ${townconf.nationId} does not exist, please change with an existing nation `
    );
    process.exit();
  }
  if (Object.keys(apxtowns).includes(townconf.townId)) {
    console.log(
      `Sorry townId ${townconf.townId} already exist, please change it`
    );
    process.exit();
  }
  /*
  if (Object.keys(apxpagans).includes(townconf.mayorId)) {
    console.log(
      `Sorry paganId ${townconf.maorId} already exist ti create a town you need a new identity, please change it`
    );
    process.exit();
  }
*/
  townconf.sudoerUser = process.env.USER;
  townconf.dirapi = path.resolve(`${__dirname}/../../`);
  // To allow to serve the nation website until the end
  townconf.nginx.include.push(
    `${townconf.dirapi}/nationchains/www/nginx_*.conf`
  );
  // To allow to serve tribes web site
  townconf.nginx.include.push(
    `${townconf.dirapi}/nationchains/tribes/*/www/nginx_*.conf`
  );
  townconf.nginx.logs = `${townconf.dirapi}/nationchains/logs/nginx`;
  townconf.nginx.website = "adminapx";
  townconf.nginx.fswww = "nationchains/"; //for a local tribe nationchains/tribes/tribeid
  townconf.nginx.tribeid = "town";
  townconf.nginx.pageindex = "index_en.html";

  console.log(townconf);
  if (
    !readlineSync.keyInYN(
      `\x1b[42mThis is the first install from ./nationchains/www/adminapx/townconf.json (check it if you want) \nthis will change your nginx config in /etc/nginx and run nginx from sudoer user ${townconf.sudoerUser}  (Yes/no)? \nno if you want to change parameter and run yarn setup again      \x1b[0m`
    )
  )
    process.exit();

  // saved and change nginx conf
  if (!fs.existsSync("/etc/nginx/nginxconf.saved")) {
    fs.moveSync("/etc/nginx/nginx.conf", "/etc/nginx/nginxconf.saved");
    console.log(
      "your previous /etc/nginx/nginx.conf was backup in  /etc/nginx/nginxconf.saved"
    );
  }
  const tplnginxconf = fs.readFileSync(
    "./nationchains/www/adminapx/nginx/nginx.conf.mustache",
    "utf8"
  );
  fs.outputFileSync(
    "/etc/nginx/nginx.conf",
    mustache.render(tplnginxconf, townconf),
    "utf8"
  );
  //proxyparam
  const proxy_params = fs.readFileSync(
    "./nationchains/www/adminapx/nginx/proxy_params.mustache",
    "utf8"
  );
  fs.outputFileSync(
    "/etc/nginx/proxy_params",
    mustache.render(proxy_params, townconf),
    "utf8"
  );
  const tplnginxwww = fs.readFileSync(
    "./nationchains/www/adminapx/nginx/modelwebsite.conf.mustache",
    "utf8"
  );
  fs.outputFileSync(
    `./${townconf.nginx.fswww}www/nginx_${townconf.nginx.website}.conf`,
    mustache.render(tplnginxwww, townconf),
    "utf8"
  );
  fs.outputJsonSync("./nationchains/tribes/conf.json", townconf, {
    spaces: 2,
  });
  // Integrer cette partie du setup en inteactif.
  // l'objectif du setup est de rendere  accessible adminapx en local (IP local) ou production IP public
  //CREATE A TOWN setup local voir utiliser towns.create
  /* townconf.town = {
    townId: townconf.townId,
    nationId: townconf.nationId,
    url: `http://${townconf.dns[0]}`,
    IP: townconf.IP,
    mayorid: townconf.mayorId,
    status: "unchain",
  };
  apxtowns[townconf.townId] = townconf.town;
  fs.outputJsonSync(`./nationchains/towns/idx/townId_all.json`, apxtowns);
  fs.outputJsonSync(
    `./nationchains/towns/itm/${townconf.townId}.json`,
    townconf.town,
    { spaces: 2 }
  );
  // Create tribe id voir a utiliser tribes.create()
  townconf.tribe = {
    tribeId: townconf.tribeId,
    dns: [],
    status: "unchain",
    nationId: townconf.nationId,
    townId: townconf.townId,
  };
  //tribe does not exist in a new town
  apxtribes = {};
  apxtribes[townconf.tribeId] = townconf.tribe;
  fs.outputJsonSync(`./nationchains/tribes/idx/tribeId_all.json`, apxtribes);
  fs.outputJsonSync(
    `./nationchains/tribes/itm/${townconf.tribeId}.json`,
    townconf.tribe,
    { spaces: 2 }
  );
  fs.ensureDirSync(`./nationchains/tribes/${townconf.tribeId}/logs/nginx`);

  //CREATE a mayorId pagans if it does not exist
  if (!apxpagans[townconf.mayorId]) {
    const Pagans = require("./Pagans");
    const createPagans = await Pagans.createId(
      townconf.mayorId,
      townconf.passphrase
    );
    if (createPagans.status == 200) {
      fs.outputFileSync(
        `./${townconf.mayorId}_PrivateKey.txt`,
        createPagans.data.privateKey,
        "utf8"
      );
      fs.outputFileSync(
        `./${townconf.mayorId}_PublicKey.txt`,
        createPagans.data.publicKey,
        "utf8"
      );
      console.log(
        `\x1b[43mCut paste your keys /${townconf.mayorId}_PrivateKey.txt /${townconf.mayorId}_PublicKey.txt \x1b[0m`
      );
    } else {
      console.log("Error at Pagan creation ");
      console.log(createPagans);
      process.exit();
    }
  }*/

  //fin de partie à integer dans l'interface graphique adminapx

  //restart nginx
  const { exec } = require("child_process");
  exec(townconf.nginx.restart, (error, stdout, stderr) => {
    if (error) {
      console.log("\x1b[42m", error, stdout, stderr, "x1b[0m");
    } else {
      console.log(
        `\x1b[42m###########################################################################################\x1b[0m\n\x1b[42mWellcome into apxtrib, you can now 'yarn dev' for dev or 'yarn startpm2' for prod or       \n'yarn unittest' for testing purpose. Access to your town here \x1b[0m\x1b[32mhttp://${townconf.dns}\x1b[0m \x1b[42m             \nto finish your town set up. Check README's project to learn more.                          \x1b[0m\n\x1b[42m###########################################################################################\x1b[0m`
      );
    }
  });
};

Setup.Checkjson = (conf) => {
  var rep = "";
  const nation_town = fs.readJsonSync(
    "./nationchains/socialworld/objects/towns/searchindex/towns_nation_uuid.json"
  );
  if (!ObjectKeys(nation_town).includes(conf.nationId)) {
    rep += `your nationId ${conf.nationId} does not exist you have to choose an existing one`;
  }
  if (nation_town[conf.nationId].includes(conf.townId)) {
    rep += `This conf.townId already exist you have to find a unique town name per nation`;
  }
  const getnation = Odmdb.get(
    "./nationchains/socialworld/objects",
    "towns",
    [conf.NationId],
    [nationId]
  );
  //if getnation.data.notfound
  conf.language.forEach((l) => {
    if (!["fr", "en", "it", "de", "sp"].includes(l)) {
      rep += l + " Only fr,en,it,de,sp are available \n";
    }
  });
  if (!fs.existsSync(`/home/${conf.sudoerUser}`)) {
    rep += `/home/${conf.sudoerUser} does not exist, user has to be create with a /home on this server\n`;
  }
  try {
    if (
      "true" ==
      execSync('timeout 2 sudo id && sudo="true" || sudo="false";echo "$sudo"')
        .toString()
        .trim()
        .split(/\r?\n/)
        .slice(-1)
    ) {
      rep += `${sudoerUser} is not sudoer please change this `;
    }
  } catch (err) {
    console.log(err);
    rep += " Check your user it seems to not be a sudoer";
  }
  if (conf.jwtsecret.length < 32) {
    rep += "Your jwtsecretkey must have at least 32 characters";
  }
  if (
    conf.dns != "unchain" &&
    !dnsSync.resolve(`${conf.townId}.${conf.nationId}.${conf.dns}`)
  ) {
    rep += `\nresolving $${conf.townId}.${conf.nationId}.${conf.dns} will not responding valid IP, please setup domain redirection IP before runing this script`;
  }
  return rep;
};

Setup.config = (townSetup) => {
  // Init this instance with a .config.js
  Setup.configjs(townSetup);
  // Create tribeid space + a user admin + webspace withe apxtrib webapp install
  Setup.druidid(townSetup);
};
Setup.configjs = (townSetup) => {
  // Set /config.js
  let confapxtrib = fs.readFileSync("./setup/config.mustache", "utf-8");
  fs.writeFileSync(
    "./config.js",
    Mustache.render(confapxtrib, townSetup),
    "utf-8"
  );
  if (fs.existsSync("./config.js")) {
    console.log("config.js successfully created.");
  } else {
    console.log(
      "config.js not created, check what's wrong in tpl:",
      confapxtrib
    );
    console.log("for data :", townSetup);
    process.exit();
  }
};
Setup.druidid = (townSetup) => {
  // create a tribeid with a user that will admin this instance into /tribes/tribeid /users
  const config = require("../config.js");
  // Need to do it on setup this is also done again in models/Tribes.js
  console.log(`${config.tribes}/${townSetup.druidid}`);
  fs.ensureDirSync(`${config.tribes}/${townSetup.druidid}`);
  ["users", "www", "referentials", "nationchains"].forEach((r) => {
    fs.copySync(
      `${__dirapi}/setup/tribes/apxtrib/${r}`,
      `${config.tribes}/${townSetup.druidid}/${r}`
    );
  });
  /*	const confcli = JSON.parse( Mustache.render( fs.readFileSync( `${__dirapi}/setup/tribes/apxtrib/clientconf.mustache`, 'utf8' ), townSetup ) );
		fs.outputJsonSync( `${config.tribes}/${townSetup.druidid}/clientconf.json`, confcli );
		// Create a new tribeid + admin user for this tribeid
		// with access to {druidid}:webapp as admin
	*/
  const Tribes = require("./Tribes.js");
  const access = { app: {}, data: {} };
  access.app[`${townSetup.druidid}:webapp`] = "admin";
  access.data[townSetup.druidid] = {
    users: "CRUDO",
    referentials: "CRUDO",
    www: "CRUDO",
  };
  const createclient = Tribes.create({
    tribeid: townSetup.druidid,
    genericpsw: townSetup.genericpsw,
    lanquageReferential: townSetup.language,
    useradmin: {
      LOGIN: townSetup.login,
      xlang: townSetup.language[0],
      ACCESSRIGHTS: access,
    },
  });
  if (createclient.status == 200) {
    console.log(
      `Your tribeid domain was created with login : ${townSetup.login} and password: ${townSetup.genericpsw}, change it after the 1st login on https://${townSetup.subdomain}.${townSetup.domain}`
    );
    // Create nginx conf for a first install
    const confnginx = fs.readFileSync(
      "./setup/nginx/nginx.conf.mustache",
      "utf8"
    );
    fs.outputFileSync(
      "/etc/nginx/nginx.conf",
      Mustache.render(confnginx, townSetup),
      "utf-8"
    );
    // Create a spacedev for webapp of apxtrib
    // that will be accesible in prod from https://subdomain.domain/ and in dev http://webapp.local.fr
    const addspaceweb = Tribes.addspaceweb({
      setup: true,
      dnsname: [`${townSetup.subdomain}.${townSetup.domain}`],
      mode: townSetup.mode,
      tribeid: townSetup.druidid,
      website: "webapp",
      pageindex: "app_index_fr.html",
    });
    if (addspaceweb.status == 200) {
      console.log(`WELL DONE run yarn dev to test then yarn startpm2 `);
    }
  } else {
    console.log("Issue ", createclient);
  }
};

