"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
const path_1 = tslib_1.__importDefault(require("path"));
const request_1 = tslib_1.__importDefault(require("request"));
const logger_1 = tslib_1.__importDefault(require("./logger"));
const constants_1 = require("../constants");
// A dead simple mutex lock.
let locked = false;
exports.assetsTablePath = path_1.default.join(process.env.TUTURE_PATH || process.cwd(), constants_1.TUTURE_ROOT, constants_1.ASSETS_JSON_PATH);
exports.assetsTableCheckpoint = path_1.default.join(process.env.TUTURE_PATH || process.cwd(), constants_1.TUTURE_ROOT, constants_1.ASSETS_JSON_CHECKPOINT);
function hasAssetsChangedSinceCheckpoint() {
    if (!fs_extra_1.default.existsSync(exports.assetsTableCheckpoint)) {
        return false;
    }
    return !fs_extra_1.default
        .readFileSync(exports.assetsTablePath)
        .equals(fs_extra_1.default.readFileSync(exports.assetsTableCheckpoint));
}
exports.hasAssetsChangedSinceCheckpoint = hasAssetsChangedSinceCheckpoint;
/**
 * Load assets from tuture-assets.json.
 * If not present, return an empty array.
 */
function loadAssetsTable() {
    if (fs_extra_1.default.existsSync(exports.assetsTablePath)) {
        return JSON.parse(fs_extra_1.default.readFileSync(exports.assetsTablePath).toString());
    }
    return [];
}
exports.loadAssetsTable = loadAssetsTable;
/**
 * Save assets back to tuture-assets.json.
 */
function saveAssetsTable(assets) {
    fs_extra_1.default.writeFileSync(exports.assetsTablePath, JSON.stringify(assets, null, 2));
}
exports.saveAssetsTable = saveAssetsTable;
/**
 * Check assets table and throw warning if some local images are not uploaded.
 */
function checkAssets(assets) {
    assets.forEach(({ localPath, hostingUri }) => {
        if (!hostingUri) {
            logger_1.default.log('warning', `${localPath} has not been uploaded. Please check your network connection.`);
        }
    });
}
exports.checkAssets = checkAssets;
/**
 * The pure operation of uploading images.
 */
function upload(localPath, callback) {
    const formData = { file: fs_extra_1.default.createReadStream(localPath) };
    request_1.default.post({ formData, url: constants_1.IMAGE_HOSTING_URL }, (err, res, body) => {
        if (err) {
            return callback(new Error('Failed to make request. Retrying ...'));
        }
        const { success, data } = JSON.parse(body);
        if (!success) {
            return callback(new Error(`Upload failed for ${localPath}.`));
        }
        callback(null, data);
    });
}
exports.upload = upload;
/**
 * Upload a single image to image hosting.
 */
function uploadSingle(localPath) {
    const newAsset = { localPath };
    if (locked) {
        return;
    }
    locked = true;
    const assets = loadAssetsTable();
    upload(localPath, (err, data) => {
        if (!err) {
            logger_1.default.log('success', `Upload ${localPath} to ${data} successfully.`);
            newAsset.hostingUri = data;
        }
        assets.push(newAsset);
        saveAssetsTable(assets);
        // Unlock anyway.
        locked = false;
    });
}
exports.uploadSingle = uploadSingle;
/**
 * Synchronize all images, including uploading all local images
 * and download images from hosting sites.
 */
function syncImages() {
    if (locked) {
        logger_1.default.log('warning', 'tuture-assets.json is being read by another program.');
        return;
    }
    locked = true;
    const assets = loadAssetsTable();
    const syncTasks = assets
        .filter(({ localPath, hostingUri }) => fs_extra_1.default.existsSync(localPath) || hostingUri)
        .map(({ localPath, hostingUri }) => new Promise((resolve) => {
        // Missing on this machine, download from image hosting.
        if (!fs_extra_1.default.existsSync(localPath)) {
            logger_1.default.log('info', `Downloading from ${hostingUri} to ${localPath}.`);
            if (!fs_extra_1.default.existsSync(path_1.default.dirname(localPath))) {
                fs_extra_1.default.mkdirpSync(path_1.default.dirname(localPath));
            }
            return request_1.default
                .get(hostingUri)
                .pipe(fs_extra_1.default.createWriteStream(localPath));
        }
        // Not uploaded yet, trying to upload.
        if (!hostingUri) {
            return upload(localPath, (err, data) => {
                if (err) {
                    return resolve({ localPath });
                }
                logger_1.default.log('success', `Upload ${localPath} to ${data} successfully.`);
                resolve({ localPath, hostingUri: data });
            });
        }
        resolve({ localPath, hostingUri });
    }));
    Promise.all(syncTasks).then((syncedAssets) => {
        // Save synced assets table if updated.
        if (JSON.stringify(assets) !== JSON.stringify(syncedAssets)) {
            saveAssetsTable(syncedAssets);
            logger_1.default.log('success', 'Synchronized assets table.');
        }
        locked = false;
    });
}
exports.syncImages = syncImages;
