/**
 * Created by Gifer on 26.07.2017.
 */

const console = require('gifer-console');
const CMD     = require('../mcconnect').CMD;
const Service = require('../service');
const fs      = require('fs');
const os      = require('os');
const crypto  = require('crypto');
const URL     = require('url');
const zlib    = require('zlib');

let __abortDownload  = null;
let dialogs          = null;
let mainWindow       = null;

// opts: { silent, onProgress } — silent глушить per-file події start/progress/complete у renderer
// (потрібно для bundle: викликач веде власний цикл на весь набір), байти віддаються в onProgress.
function download(url, path, onError, opts) {
    return new Promise(function (resolve, reject) {
        let protocol  = url.indexOf('https://') === 0 ? 'https' : 'http';
        let pUrl      = URL.parse(url);
        let http      = require(protocol);
        let finalHash = null;
        let rayID     = Service.RandomHash(10);

        if (path) {
            if (!opts || !opts.silent) {
                mainWindow.webContents.send('ec_CMD', [
                    CMD.ec_file_download_start,
                    [ rayID, 'http' ]
                ]);
            }

            fs.open(path, 'w', (err, fd) => {
                if (err) {
                    onError(CMD.errElectron.eFileDownload, [err.message]);

                    reject(err.message);
                } else {
                    let file = fs.createWriteStream(path, { fd: fd });

                    process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // на сервере можем юзать самоподписной сертификат :(

                    pUrl.headers = {
                        "Accept-Encoding": "gzip"
                    };
                    pUrl.gzip = true;

                    http.get(pUrl, function(res) {
                        function sendProgressInfo() {
                            currentPercent = (totalLength / onePercent).toFixed();

                            if (opts && opts.silent) {
                                // прогрес агрегує викликач: лише він знає загальний розмір усього набору
                                if (opts.onProgress) {
                                    opts.onProgress(totalLength);
                                }

                                return;
                            }

                            if (mainWindow && !mainWindow.isDestroyed()){
                                try {
                                    mainWindow.webContents.send('ec_CMD', [
                                        CMD.ec_file_download_progress,
                                        {
                                            size    : Service.format_size(fileSize),
                                            text    : Service.format_size(totalLength),
                                            percent : currentPercent,
                                            name    : Service.ExtractFileName(path),
                                            url     : url,
                                            rayID   : rayID
                                        }
                                    ]);
                                } catch (e) {}
                            }
                        }

                        function end(){
                            file.close();

                            if (sha1) {
                                finalHash = sha1.digest('hex');
                            }

                            if ((!opts || !opts.silent) && mainWindow && !mainWindow.isDestroyed()){
                                try{
                                    mainWindow.webContents.send('ec_CMD', [
                                        CMD.ec_file_download_complete,
                                        rayID
                                    ]);
                                } catch (e) {}
                            }

                            __abortDownload = null;

                            process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';

                            resolve([path, finalHash, totalLength]);
                        }

                        let progressTimer  = null;
                        let fileSize       = res.headers['content-length'];
                        let onePercent     = fileSize / 100;
                        let currentPercent = 0;
                        let totalLength    = 0;
                        let sha1           = crypto.createHash('sha1');

                        if (res.statusCode === 404){
                            file.close();

                            let err = "Error 404: File not found!";

                            fs.unlink(path, function () {
                                __abortDownload = null;

                                onError(CMD.errElectron.eFileDownload, [err]);

                                process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
                            });

                            if (mainWindow && !mainWindow.isDestroyed()){
                                try {
                                    mainWindow.webContents.send('ec_CMD', [ // обрабатывается в системе обновлений
                                        CMD.ec_file_download_file_not_found,
                                        url
                                    ]);
                                } catch (e) {}
                            }

                            reject(err);
                        } else {
                            process.nextTick(sendProgressInfo);

                            __abortDownload = function () {
                                res.pause();
                                res.destroy();

                                sha1 = null;

                                file.close();

                                fs.unlink(path, function () {
                                    if (mainWindow && !mainWindow.isDestroyed()){
                                        try {
                                            mainWindow.webContents.send('ec_CMD', [
                                                CMD.ec_file_download_aborted,
                                                rayID
                                            ]);
                                        } catch (e) {}
                                    }

                                    process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
                                });
                            };

                            res.on('data', (chunk) => {
                                totalLength += chunk.length;

                                if (sha1) {
                                    sha1.update(chunk);
                                }

                                if (!progressTimer){
                                    progressTimer = setTimeout(function () {
                                        sendProgressInfo();

                                        progressTimer = null;
                                    }, 100);
                                }
                            });

                            res.on('error', (err) => {
                                file.close();
                                sha1 = null;

                                fs.unlink(path, function () {
                                    __abortDownload = null;

                                    onError(CMD.errElectron.eFileDownload, [err.message]);

                                    process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
                                });

                                reject(err.message);
                            });

                            if (res.headers["content-encoding"] && res.headers["content-encoding"].indexOf("gzip") >= 0) {
                                var unzip = zlib.createUnzip();

                                unzip.on('end', end);

                                res.pipe(unzip).pipe(file);
                            } else {
                                res.on('end', end);

                                res.pipe(file);
                            }
                        }
                    }).on('error', function(err) {
                        file.close();

                        fs.unlink(path, function () {
                            __abortDownload = null;

                            onError(CMD.errElectron.eFileDownload, [err.message]);

                            process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
                        });

                        reject(err.message);
                    });
                }
            });
        } else {
            reject('Download: file name is not set or downloading aborted');
        }
    });
}

function findCopy(_path, _name) {
    let copyIDX  = 0;
    let findNext = (filePath, fileName) => {
        fileName = copyIDX
            ? fileName.indexOf('.') >= 1 ? fileName.replace('.', ` (${copyIDX}).`) : fileName + ` (${copyIDX})`
            : fileName;

        try {
            let info = fs.statSync(filePath + fileName);

            if (info && info.isFile()){
                copyIDX ++;

                return findNext(filePath, _name);
            }
            if (info && info.isDirectory()){
                return fileName;
            } else {
                return fileName;
            }
        } catch (e) {
            return fileName;
        }
    };
    
    return new Promise(function (resolve) {
        resolve(findNext(_path, _name));
    });
}

function openDialogDownload(path, file, openDialog) {
    return new Promise(function (resolve, reject) {
        if (dialogs){
            let openPath = "";
            let dPath    = file || "";

            if (os.platform() === 'win32') {
                openPath = path.replace(/\//g, '\\');

                if (openPath[openPath.length - 1] !== '\\'){
                    openPath += "\\";
                }
            } else {
                openPath = path.replace(/\\/g, '/');

                if (openPath[openPath.length - 1] !== '/'){
                    openPath += "/";
                }
            }

            findCopy(openPath, file).then(function (findName) {
                try {
                    dPath = decodeURI(openPath + (findName || ""));
                } catch (e) {
                    console.err(e.message);
                    console.err("decodeURI incorrect path: " + openPath + (findName || ""));
                }

                dialogs[openDialog ? "showOpenDialog" : "showSaveDialog"](mainWindow, {
                    defaultPath: dPath,
                    properties : ['openDirectory']
                }).then(function ({canceled, filePath}) {
                    resolve(filePath, canceled);
                });
            })
        } else {
            reject('[downloadFile]: dialogs is undefined!');
        }
    });
}

function abortDownload() {
    if (__abortDownload){
        __abortDownload();
    }
}

function init(_dialog, _mainWindow) {
    dialogs    = _dialog;
    mainWindow = _mainWindow;
}

module.exports = function () {
    init.apply(null, arguments);
    
    return {
        init,
        download,
        abortDownload,
        openDialogDownload
    }
};

