// Based on https://github.com/lafin/node-targz
// MIT license

const fs = require("fs");
const tar = require('tar-fs');
const zlib = require("zlib");
const { join, dirname, sep } = require("path");
const { exists, mkdir, unlink, stat } = require("fs-extra");
const { getRuntimePackageDirectory, getRuntimeAppsDirectory } = require("./runtimePackages");

module.exports.createTarGzPackage = async (config, appName) => {

    const appPath = join(config.latestPackagesFolder, appName);
    const distPath = join(appPath, "dist");

    if(!await exists(distPath)) {
        await mkdir(distPath);
    }

    const packagePath = `${distPath}/package.tar.gz`;
    if(await exists(`${packagePath}`)) {
        await unlink(packagePath);
    }

    try {
        await compress(appPath, packagePath);
    }catch(e){
        console.log(e);
    }
    const size = (await stat(packagePath)).size;
    return {size, path:packagePath};
}

module.exports.unzipTarGzPackageToRuntime = async (context, src, appName, versionId) => {
    const versionDir = getRuntimePackageDirectory(context, appName, versionId);
    const appDir = getRuntimeAppsDirectory(appName);

    if(await exists(appDir)) {
        if(await exists(versionDir)) {
            await remove(versionDir);
        }
    } else {
        await mkdir(appDir);
    }

    await mkdir(versionDir);

    await decompress(src, versionDir);
}

const compress = (src, dest) => new Promise((resolve, reject) => {

    // ensure opts
    opts = {src, dest};
    opts.tar = {ignore: name => dirname(name).split(sep).pop() === "dist"  || dirname(name).split(sep).pop() === "node_modules"};
    opts.gz = opts.gz || {};

    // default gzip config
    opts.gz.level = opts.gz.level || 6;
    opts.gz.memLevel = opts.gz.memLevel || 6;

    // ensure src and dest
    if(!opts.src) return reject("No source for compress!");
    if(!opts.dest) return reject("No destination for compress!");

    // go
    process.nextTick(function () {
        tar.pack(opts.src, opts.tar)
            .on('error', reject)
            .pipe(zlib.createGzip(opts.gz)
                .on('error', reject))
            .pipe(fs.createWriteStream(opts.dest)
                .on('error', reject)
                .on('finish', resolve));
    });
});

const decompress = (src, dest) => new Promise((resolve, reject) => {

    // ensure opts
    opts = {src, dest};
    opts.tar = opts.tar || {};
    opts.gz = opts.gz || {};

    // ensure src and dest
    if(!opts.src) return reject("No source for decompress!");
    if(!opts.dest) return reject("No destination for decompress!");

    // go
    process.nextTick(function () {
        fs.createReadStream(opts.src)
            .on('error', reject)
            .pipe(zlib.createGunzip(opts.gz)
                .on('error', reject))
            .pipe(tar.extract(opts.dest, opts.tar)
                .on('error', reject)
                .on('finish', resolve));
    });
});