var path = require('path');
var fs = require('fs');
var http = require('http');

var urlParse = require('url').parse;

var app = require('app');

var JSZip = require('jszip');
var mkdirs = require('node-mkdirs');
var httpreq = require('httpreq');

const commons = require('./commons');
const UPDATES_DIR = commons.UPDATES_DIR;
const APP_DIR = commons.APP_DIR;

var handlingDownload = false;

mkdirs(UPDATES_DIR);

function walk(anyPath) {
    if (!path.isAbsolute(anyPath)) {
        anyPath = path.join(__dirname, anyPath)
    }
    var stats = fs.statSync(anyPath);
    if (stats.isFile()) {
        return [anyPath]
    } else if (stats.isDirectory()) {
        return fs.readdirSync(anyPath)
            .filter((name) => {
                return name != "." && name != "..";
            })
            .map((name) => {
                return walk(path.join(anyPath, name))
            })
            .reduce((x, y) => {
                return x.concat(y);
            }, [])
    } else {
        return []
    }
}

function compress(inPath, zipFilePath) {
    var zip = new JSZip();

    var files = walk(inPath);

    files.map((filePath) => {
        var relPath = path.relative(inPath, filePath);
        zip.file(relPath, fs.readFileSync(filePath), {binary: true})
    });

    fs.writeFileSync(
        zipFilePath,
        zip.generate({compression: 'DEFLATE', base64: false}),
        'binary'
    )
}

function decompress(zipFilePath, dirPath) {
    var zip = new JSZip(fs.readFileSync(zipFilePath, 'binary'));
    zip.filter((relativePath, file) => {
        if (file.dir) return;
        var absPath = path.join(dirPath, relativePath);
        mkdirs(path.dirname(absPath));
        fs.writeFileSync(absPath, file.asBinary(), 'binary');
        console.log(absPath);
    })
}

function cleanLocalUpdates() {
    fs.readdirSync(UPDATES_DIR).map((p) => {
        if (p == '.' || p == '..') return;
        fs.unlinkSync(path.join(UPDATES_DIR, p));
    });
}

function downloadUpdate(url) {
    if(handlingDownload) {
        return console.log('downloading or done. skip this')
    }
    var fileName = path.basename(urlParse(url).pathname);
    if (!fileName) return;

    try {
        var targetPath = path.join(UPDATES_DIR, fileName);
        if (fs.existsSync(targetPath)) {
            fs.unlinkSync(targetPath)
        }

        httpreq.download(
            url,
            targetPath,
            (e, progress) => {
                console.log('progress', e, progress);
                handlingDownload = true;
            }, (e, res) => {
                if (e) return console.log('res', e, res);
            }
        )
    } catch (e) {
        console.log('downloadUpdate error', e);
    }

}

var feedUrl = null;

function setFeedUrl(url) {
    feedUrl = url;
}

function checkRemoteOnce() {
    if (!feedUrl) return;

    httpreq.get(feedUrl, (err, res) => {
        if (err) return;
        try {
            var data = JSON.parse(res.body);
            if (data.url) {
                downloadUpdate(data.url);
            }
        } catch (e) {
            console.error('checkRemoteOnce', e);
        }
    });
}

function checkRemoteUpdates(delay) {
    setInterval(
        checkRemoteOnce, delay
    );
    checkRemoteOnce();
}

function compareVersion(ver1, ver2) {
    try {
        return R.compose(
            R.head,
            R.filter(d=>d != 0),
            R.map(d=>R.map(v=>parseInt(v), d).reduce(R.subtract)),
            R.zip
          )(ver1.split('.'), ver2.split('.')) || ver1.length - ver2.length
    } catch (e) {
        return -2
    }
}

function checkLocalUpdates() {
    var updates = fs.readdirSync(UPDATES_DIR);
    if (!updates.length) return null;

    updates.sort();
    var versions = updates.map((p) => {
        return path.basename(p, '.zip')
    });
    var latestVersion = versions[versions.length - 1];

    if (compareVersion(app.getVersion(), latestVersion) < 0) {
        // 发现新升级文件
        return path.join(UPDATES_DIR, `${latestVersion}.zip`);
    } else {
        // 全都是老文件，进行删除；
        cleanLocalUpdates();
    }
    return null;
}


function installUpdate(updateFile) {
    try {
        decompress(updateFile, APP_DIR);
        cleanLocalUpdates();
        return true
    } catch (e) {
        console.log("installUpdate error:", e);
        cleanLocalUpdates();
        return false
    }
}

module.exports = {
    setFeedUrl,
    checkRemoteUpdates,
    checkLocalUpdates,
    installUpdate
};

//compress(path.join(__dirname, '../build/out'), path.join(__dirname,'../build/out.zip'));
//decompress('../build/out.zip', '../build/out2');

//console.log(checkLocalAndUpdate());