var express = require("express");
var app = new express();
var bodyParser = require('body-parser')
var opn = require("opn");
var storage = require("node-persist"); // library for read/write account on local container
var signale = require('signale'); // library for handling the output rendering process
var mainFunctions = require("./main"); //get all modules on "main" file
var fs = require("fs");
var Path = require('path');

var isLogged = false;
var isBlocked = false;

var listDocuments = [];

// Setting up the web mode directory
app.use(express.static('webMode'));
app.use(bodyParser.json());

function startServer() {

    app.listen(8080, function () {
        signale.success("Server started!");

        //Open web mode in browser
        opn("http://localhost:8080");

        app.post("/getList", function (req, res) {

            try {
                var accounts = mainFunctions.getAccounts(req.body.masterPassword);
                if (accounts == null) {
                    res.send({ error: "Master password is not correct!" });
                } else {
                    res.send(accounts);
                }
            } catch (err) {
                throw err;
            }
        });

        app.get("/generatePassword", function (req, res) {
            try {
                var newPassword = mainFunctions.generatePassword();
                signale.success("Password generated: " + newPassword);
                res.send("Password generated: " + newPassword);
            } catch (err) {
                throw err;
            }
        });

        app.post("/createAccount", function (req, res) {

            try {
                var account = mainFunctions.getAccount(req.body.account.name, req.body.masterPassword);
                if (account != null) {
                    res.send({ error: "This account already exist. If you want, you can modify it" });
                } else {

                    var newAccount = mainFunctions.createAccount(req.body.account, req.body.masterPassword);
                    signale.info(newAccount)
                    if (newAccount) {
                        signale.success("Account " + newAccount.name + " created!");
                        res.send("Account " + newAccount.name + " created!");
                    } else {
                        res.send({ error: "Master password is not correct!" });
                    }
                }
            } catch (err) {
                throw err;
            }
        })

        app.post("/getAccount", function (req, res) {

            try {
                var account = mainFunctions.getAccount(req.body.name, req.body.masterPassword);
                if (account != null) {

                    signale.success("Account matched!");

                    var accountFinded = {};
                    accountFinded.name = account.name;
                    accountFinded.username = account.username;
                    accountFinded.password = account.password;
                    accountFinded.isFavorite = account.isFavorite;

                    res.send(accountFinded);

                } else {
                    res.send({ error: "Your Data is Wrong" });
                }
            } catch (err) {
                throw err;
            }
        });

        app.post("/modifyAccount", function (req, res) {

            try {
                var account = mainFunctions.getAccount(req.body.account.name, req.body.masterPassword);
                if (account != null) {
                    signale.success("Account matched!");

                    var newAccount = mainFunctions.modifyAccount(account,
                        req.body.account, req.body.masterPassword);

                    if (newAccount.length == 0) {
                        res.send({ error: "Missing parameters!" });
                    } else {
                        signale.success("Account changed!")
                        res.send(newAccount);
                    }
                } else {
                    res.send({ error: "Your Data is Wrong" });
                }
            } catch (err) {
                throw err;
            }
        });

        app.post("/deleteAccount", function (req, res) {

            try {
                var account = mainFunctions.getAccount(req.body.name, req.body.masterPassword);
                if (account != null) {

                    mainFunctions.deleteAccount(req.body.name, req.body.masterPassword);
                    signale.success("Account " + req.body.name + " deleted!");
                    res.send("Account " + req.body.name + " deleted!");

                } else {
                    res.send({ error: "Your Data is Wrong" });
                }
            } catch (err) {
                throw err;
            }
        });

        app.post("/deleteAll", function (req, res) {
            try {

                //Is not necessary but it is for control masterpassword
                var accounts = mainFunctions.getAccounts(req.body.masterPassword);
                if (accounts == null) {
                    res.send({ error: "Master password is not correct!" });
                } else {

                    //delete all data on memory and write empty accounts
                    mainFunctions.saveAccounts([], req.body.masterPassword);

                    res.send("Accounts deleted!");
                }
            } catch (err) {
                throw err;
            }
        });

        app.get("/backup", function (req, res) {

            try {
                //Get account container
                var data = storage.getItemSync("accounts");

                //if not exist backup folder
                var dir = "./backup";
                if (!fs.existsSync(dir)) {
                    fs.mkdirSync(dir); // create it
                }

                //if not exist backup folder of docs
                var dirDocs = "./backup/docs";
                if (!fs.existsSync(dirDocs)) {
                    fs.mkdirSync(dirDocs); // create it
                }

                //create backup accounts 
                fs.writeFile("./backup/backup.txt", data, function () {

                    // directory path
                    var dir = "./docs/";

                    //create backup docs
                    fs.readdir(dir, async (err, files) => {
                        if (files.length > 0) {
                            for (var index = 0; index < files.length; index++) {
                                var file = files[index];

                                //copy original file into backup folder
                                fs.copyFile(dir + file, dirDocs + "/" + file, (err) => {
                                    if (err) throw err;
                                });

                                if (index == files.length - 1) {
                                    res.send("Backup created!");
                                }
                            }
                        } else  {

                            //if there are not docs, backup completed
                            res.send("Backup created!");
                        }
                    })
                })
            } catch (err) {
                throw err;
            }
        });

        app.get("/getInfoLastBackup", function(req, res) {

            //if backup not exist
            if (!fs.existsSync("./backup") && !fs.existsSync("./backup/backup.txt"))  {
                res.send(null);
            } else {
                //read properties of backup file
                fs.stat("./backup/backup.txt", {}, function (err, data) {
                    if(err) {
                        throw err;
                    }

                    res.send({"lastMod": data.mtime.toISOString().replace(/T/, ' ').      // replace T with a space
                    replace(/\..+/, ''), "today": new Date().toISOString().replace(/T/, ' ').      // replace T with a space
                    replace(/\..+/, '')})   // delete the dot and everything after);
                })
            }
        })

        app.get("/restore", function (req, res) {

            try {
                if (!fs.existsSync("./backup") && !fs.existsSync("./backup/backup.txt") && !fs.existsSync("./backup/docs")) {
                    res.send("You not have a backup");
                } else {

                    //read backup file
                    fs.readFile("./backup/backup.txt", "", function (err, data) {
                        if(err) {
                            throw err;
                        }
                        storage.setItemSync("accounts", data.toString()); //insert into file on file system called "accounts" the entire array

                        //if backup folder of document exist
                        var dir = "./backup/docs";
                        if (fs.existsSync(dir)) {

                            //if not exist original folder of docs
                            var dirDocs = "./docs";
                            if (!fs.existsSync(dirDocs)) {
                                fs.mkdirSync(dirDocs); // create it for create files
                            }
                            
                            //restore docs
                            fs.readdir(dir, async (err, files) => {
                                if (files.length > 0) {
                                    for (var index = 0; index < files.length; index++) {
                                        var file = files[index];

                                        //copy backup file into original folder
                                        fs.copyFile(dir + "/" + file, dirDocs + "/" + file, (err) => {
                                            if (err) throw err;
                                        });

                                        if (index == files.length - 1) {
                                            res.send("Restore completed!");
                                        }
                                    }
                                } else {

                                    //if there are not docs, backup completed
                                    res.send("Backup created!");
                                }
                            })
                        } else  {
                            res.send("Accounts restored!");
                        }
                    })
                }
            } catch (err) {
                throw err;
            }
        });

        app.get("/checkBackup", function (req, res) {

            try {
                if (!fs.existsSync("-/backup") && !fs.existsSync("./backup/backup.txt")) {
                    res.send({ error: "You not have a backup" });
                } else {
                    res.send("Ok");
                }
            } catch (err) {
                throw err;
            }
        });

        app.get("/downloadBackup", function(req, res)   {
            fs.readFile("./backup/backup.txt", "", function (err, data) {
                if(err) {
                    throw err;
                }
                signale.success("Backup downloaded");
                res.send(data);
            })
        });

        app.post("/checkQRCode", function (req, res) {

            try {
               
               var accounts = mainFunctions.getAccounts(req.body.masterPassword);
               if (accounts == null) {
                   res.send({ error: "Master password is not correct!" });
               } else {
                isLogged = true;
                res.send(true);
               }
            } catch (err) {
                throw err;
            }
        });
        
        // conrol if user is logged with his masterpassword
        app.get("/checkLogin", function(req,res)   {

            if(isLogged)    {
                res.send(true);
            } else  {
                res.send(false);
            }
        })

        //control if application is blocked ( for control it after refresh page )
        app.get("/blockStatus", function(req, res)  {
            
            if(isBlocked)    {
                isBlocked = true;
                res.send(true);
            } else  {
                isBlocked = false;
                res.send(false);
            }
        })

        app.post("/setLogin", function(req,res)   {

            isLogged = req.body.state;
            res.send("Ok");
        })

        app.post("/setBlockStatus", function(req, res)  {

            isBlocked = req.body.state;
            res.send("Ok");

        })

        app.get("/deleteForNewUser", function (req, res) {

            try {
                const pathPersist = "./persist";
                const pathDocuments = "./docs";
                const pathBackup = "./backup";
                let deleteOk = false;

                //delete folders contents
                deleteOk = deleteFolderRecursive(pathPersist);
                deleteOk = deleteFolderRecursive(pathBackup);
                deleteOk = deleteFolderRecursive(pathDocuments);

                //remove data and masterpassword from file accounts on filesystem
                storage.removeItem("accounts");
                
                res.send(deleteOk);
            } catch (err) {
                throw err;
            }
        });

        app.post("/encryptDocument", function (req, res) {

            try {
                //Is not necessary but it is for control masterpassword
                var accounts = mainFunctions.getAccounts(req.body.masterPassword);
                if (accounts == null) {
                    res.send({ error: "Master password is not correct!" });
                } else {

                    //If there is not accounts, save your first master password (no accounts or first access )
                    if(accounts.length == 0)    {
                        mainFunctions.saveAccounts([], req.body.masterPassword);
                    }

                    //Get data of file
                    var dataFile = req.body.dataFile;

                    //Encrypt document data
                    var dataEncrypted = mainFunctions.encryptDocument(dataFile, req.body.masterPassword)

                    //If doc folder not exist, create it
                    var dir = "./docs";
                    if (!fs.existsSync(dir)) {
                        fs.mkdirSync(dir);
                    }

                    //Write file with data encrypted
                    fs.writeFile("./docs/" + req.body.name, dataEncrypted.toString(), function () {
                        res.send("doc encrypted!");
                    })
                }
            } catch (err) {
                throw err;
            }
        });

        app.post("/getDocumentList", function(req, res)  {
            try {

                //if is requested a specific file
                let nameFile = req.body.nameDocument;

                listDocuments = [];

                //Is not necessary but it is for control masterpassword
                var accounts = mainFunctions.getAccounts(req.body.masterPassword);
                if (accounts == null) {
                    res.send({ error: "Master password is not correct!" });
                } else {

                    // directory path
                    var dir = "./docs/";

                    // list all files in the directory
                    fs.readdir(dir, async (err, files) => {

                        if (!files || files.length == 0) {
                            res.send(listDocuments);
                        } else {

                            //if is not request a specific file
                            if (!nameFile) {

                                // files object contains all files names
                                // log them on console
                                for (var index = 0; index < files.length; index++) {
                                    var file = files[index];

                                    await readFileEncrypted(dir, file, req.body.masterPassword);

                                    if (index == files.length - 1) {
                                        res.send(listDocuments);
                                    }
                                }
                            } else {

                                // files object contains all files names
                                // log them on console
                                for (var index = 0; index < files.length; index++) {
                                    var file = files[index];

                                    //if is the same requested
                                    if (file == nameFile) {
                                        await readFileEncrypted(dir, file, req.body.masterPassword);
                                        res.send(listDocuments);
                                    } 
                                }
                            }
                        }
                    });
                }
            } catch (err) {
                throw err;
            }
        })

        app.post("/deleteDocument", function(req, res)  {
            var pathDocs = "./docs/";
            try {
                fs.readFile(pathDocs + req.body.nameFile, "", function (err, data) {

                    if(err) {
                        res.send({error: "No file found"});
                    } else  {
                        fs.unlinkSync(pathDocs + req.body.nameFile);
                        res.send("Ok")
                    }
                })
                
            } catch (err) {
                throw err;
            }
        })

        app.get("/checkVersion", function(req, res)  {
            try {

                var pjson = require('../package.json');
                res.send(pjson.version);
                
            } catch (err) {
                throw err;
            }
        })

    });
}

/**
 * delete all content of folder
 * @param {*} pathPersist -> path where delete all content
 */
function deleteFolderRecursive (pathPersist) {
    if (fs.existsSync(pathPersist)) {
        fs.readdirSync(pathPersist).forEach((file) => {
            const curPath = Path.join(pathPersist, file);
            if (fs.lstatSync(curPath).isDirectory()) { // recurse
                deleteFolderRecursive(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
                return true;
            }
        });
    }
};

/**
 * Read encrypted file
 * @param {*} dir -> current dir
 * @param {*} file -> file name
 * @param {*} masterPassword -> master password
 */
async function readFileEncrypted(dir, file, masterPassword) {
    return new Promise((resolve, reject) => {

        fs.readFile(dir + file, "", function (err, data) {

            //Decrypt document data
            data = mainFunctions.decryptDocument(data.toString(), masterPassword)
            listDocuments.push({ name: file, data: data });
            resolve();
        })
    })
}

exports.startServer = startServer;