const fetch = require('node-fetch');
const fs = require('fs');
const process = require('process')
const { spawnSync } = require('child_process');
const constants = require(".././constants_local.json")
const kafka = require('kafka-node')
const winston = require('winston')
const { createLogger, format, transports } = winston;


function updateConfig() {
    console.log("Retrieving primary IP");
    let file = JSON.parse(fs.readFileSync('./config.json', { encoding: 'utf-8' }))
    const getIP = spawnSync("ip", ["route", "get", file.master_node]);
    let err = getIP.stderr.toString().trim()
    if (err !== '') {
        console.log(err);
        process.exit(1);
    }
    let data = getIP.stdout.toString().trim()
    data = data.substr(0, data.indexOf("\n")).trim()
    data = data.split(' ')
    
    file.id = data[data.length - 1]
    fs.writeFileSync('./config.json', JSON.stringify(file));
    console.log("Updated Config file");   
    console.log("updateconfig file ", file)
}

function makeTopic(id) {
    console.log("Using Primary IP", id, "as topic", "publishing to:", constants.network.external.kafka_host);
    
    let client = new kafka.KafkaClient({
        kafkaHost: constants.network.external.kafka_host,
        autoConnect: true
    }),
    Producer = kafka.Producer,
    producer = new Producer(client)
    return new Promise((resolve, reject) => {
        producer.send([{
            topic: id,
            messages: JSON.stringify({
                status: "success",
            })
        }], (err, data) => { 
            if (err)
                reject();
            else
                resolve(); 
        })
    })
}

// var download = function (url, dest, check = true, cb) {
//     return new Promise((resolve, reject) => {
//         console.log(url);
//         if (!check || !fs.existsSync(dest)) {
//             var file = fs.createWriteStream(dest);
//             var request = https.get(url, function (response) {
//                 response.pipe(file);
//                 file.on('finish', function () {
//                     file.close(cb);  // close() is async, call cb after close completes.
//                     resolve();
//                 });
//             }).on('error', function (err) { // Handle errors
//                 fs.unlink(dest); // Delete the file async. (But we don't check the result)
//                 logger.error("download failed" + err.message);
                
//                 if (cb) cb(err.message);
//                 reject(err);
//             });
//         } else {
//             resolve();
//         }
//     })
    
// };

const download = (async (url, path, check = true) => {
    
    if (!check || !fs.existsSync(path)) {
        console.log(url);
        const res = await fetch(url);
        const fileStream = fs.createWriteStream(path);
        await new Promise((resolve, reject) => {
            res.body.pipe(fileStream);
            res.body.on("error", (err) => {
                reject(err);
            });
            fileStream.on("finish", function () {
                resolve();
            });
        });
    }
});

function makeid(length) {
    var result = '';
    var characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
    var charactersLength = characters.length;
    for (var i = 0; i < length; i++) {
        result += characters.charAt(Math.floor(Math.random() * charactersLength));
    }
    return result;
}

function returnPort(port, usedPort) {
    usedPort.delete((port))
}

const logger = winston.createLogger({
    level: 'info',
    format: winston.format.combine(
        format.timestamp(),
        format.json()
    ),
    defaultMeta: { module: 'Dispatch Agent' },
    transports: [
        //
        // - Write to all logs with level `info` and below to `combined.log` 
        // - Write all logs error (and below) to `error.log`.
        //
        new winston.transports.File({ filename: 'log/error.log', level: 'error' }),
        new winston.transports.File({ filename: 'log/combined.log' }),
        new winston.transports.Console({
            format: winston.format.combine(
                format.colorize({ all: true }),
                format.timestamp(),
                format.simple()

            )
        })
    ]
});


function getPort(usedPort) {
    let port = -1, ctr = 0
    do {
        let min = Math.ceil(30000);
        let max = Math.floor(60000);
        port = Math.floor(Math.random() * (max - min + 1)) + min;
        ctr += 1;
        if (ctr > 30000) {
            port = -1
            break
        }
    } while (usedPort.has(port))
    return port
 }

module.exports = {
    download, makeid, updateConfig, makeTopic, returnPort, logger
}
