"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var m = o[Symbol.asyncIterator], i;
    return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ora_1 = __importDefault(require("ora"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const cross_spawn_1 = __importDefault(require("cross-spawn"));
const _directorys_1 = __importDefault(require("../utils/_directorys"));
const _fsUtils_1 = require("../utils/_fsUtils");
const _logUtils_1 = require("../utils/_logUtils");
const liveReload_1 = require("../reload/liveReload");
const _sleep_1 = __importDefault(require("../utils/_sleep"));
const updateData_1 = __importDefault(require("../updateData/updateData"));
const styleLinking_1 = __importDefault(require("../style-linking/styleLinking"));
const removeDistDirectory = () => __awaiter(void 0, void 0, void 0, function* () {
    const spinner = (0, ora_1.default)('Cleaning up distribution directory').start();
    // this gets wrapped in its own try...catch as we don't want to fail the build.
    try {
        const productionDirectory = yield fs_extra_1.default.readdir(_directorys_1.default.productionRoot);
        if (productionDirectory.length) {
            yield fs_extra_1.default.remove(_directorys_1.default.productionRoot);
        }
        spinner.succeed('Distribution directory sanitized');
        return;
    }
    catch (_a) {
        spinner.succeed('Distribution directory sanitized');
        return;
    }
});
/**
 * Builds the dist directory and returns a voided promise, to be called
 * asynchronously, before we can do anything else.
 */
const buildDistDirectory = () => __awaiter(void 0, void 0, void 0, function* () {
    const spinner = (0, ora_1.default)('Creating distribution directory').start();
    // Array of directories contained in the dist folder for Shopify.
    const directoriesToMake = [
        _directorys_1.default.productionRoot,
        _directorys_1.default.distAssetsRoot,
        _directorys_1.default.distConfigRoot,
        _directorys_1.default.distLayoutRoot,
        _directorys_1.default.distLocalesRoot,
        _directorys_1.default.distSectionsRoot,
        _directorys_1.default.distSnippetsRoot,
        _directorys_1.default.distTemplatesRoot,
        _directorys_1.default.distCustomersRoot,
    ];
    const created = [];
    for (const directory of directoriesToMake) {
        created.push(yield (0, _fsUtils_1.createDirectory)(directory));
    }
    // If any of the directories failed creating, it will be contained in the created array.
    if (created.includes(false)) {
        spinner.fail('Failed creating distribution directory, maybe it already exists');
        throw new Error('Error creating the distribution directory');
    }
    return spinner.succeed('Finished creating distribution directory');
});
/**
 * Function to copy files to the Dist directory on build.
 * @param directory - String
 * @param output - String
 * @param type - String
 * @returns Promise<Ora>
 */
const copyToDist = (directory, output, type) => __awaiter(void 0, void 0, void 0, function* () {
    const spinner = (0, ora_1.default)(`Moving ${type} to ${output}`).start();
    // Gets its own try...catch statement, so we don't fail the build step.
    try {
        yield (0, _fsUtils_1.cloneDirectory)(directory, output);
        return spinner.succeed(`Finished moving ${type} to ${output}`);
    }
    catch (err) {
        console.error(err);
        return spinner.fail(`Error moving ${type} to ${output}`);
    }
});
const runWebpackBuild = () => __awaiter(void 0, void 0, void 0, function* () {
    const webPackSpinner = (0, ora_1.default)('Packing styles and scripts with Webpack').start();
    const command = (0, cross_spawn_1.default)('npx', ['webpack', '--config', `webpack.production.config`]);
    const strings = {
        errorString: 'There was an error in Webpack, maybe it still compiled - check the logging output above',
        successString: 'Finished packing output files',
    };
    command.stdout.on('data', (data) => __awaiter(void 0, void 0, void 0, function* () {
        (0, _logUtils_1.spawnCallback)(data, false);
        const outputString = data.toString().toLowerCase();
        if (outputString.includes('error')) {
            webPackSpinner.warn(strings.errorString);
            yield (0, styleLinking_1.default)(null);
            return process.exit(1);
        }
        if (outputString.includes('compiled successfully')) {
            webPackSpinner.succeed();
            yield (0, styleLinking_1.default)(null);
            return process.exit(1);
        }
    }));
    command.stderr.on('data', (data) => {
        (0, _logUtils_1.spawnCallback)(data, false);
        return webPackSpinner.warn(strings.errorString);
    });
    command.stdout.on('end', () => __awaiter(void 0, void 0, void 0, function* () {
        yield (0, styleLinking_1.default)(null);
        return webPackSpinner.succeed('Finished packing styles and scripts');
    }));
    command.on('error', (err) => __awaiter(void 0, void 0, void 0, function* () {
        webPackSpinner.fail('Error packing styles and scripts');
        (0, _logUtils_1.handleError)(err.errno, err);
        yield (0, styleLinking_1.default)(null);
    }));
    return;
});
/**
 * The main func for building the dist directory from the build command.
 * @param options
 */
const buildDistFiles = (options) => __awaiter(void 0, void 0, void 0, function* () {
    var e_1, _b, e_2, _c;
    const spinner = (0, ora_1.default)('Building distribution folder.').start();
    try {
        // Update the settings_data.json if --env is passed.
        if (options.environment) {
            yield (0, updateData_1.default)(options);
        }
        // The directories array we want to use to copy from src to dist.
        const directoriesToCopy = [
            {
                from: _directorys_1.default.staticRoot,
                to: _directorys_1.default.distAssetsRoot,
                name: 'Static',
            },
            {
                from: _directorys_1.default.imagesRoot,
                to: _directorys_1.default.distAssetsRoot,
                name: 'Images',
            },
            {
                from: _directorys_1.default.fontsRoot,
                to: _directorys_1.default.distAssetsRoot,
                name: 'Fonts',
            },
            {
                from: _directorys_1.default.configRoot,
                to: _directorys_1.default.distConfigRoot,
                name: 'Config',
            },
            {
                from: _directorys_1.default.layoutRoot,
                to: _directorys_1.default.distLayoutRoot,
                name: 'Layout',
            },
            {
                from: _directorys_1.default.localesRoot,
                to: _directorys_1.default.distLocalesRoot,
                name: 'Locales',
            },
            {
                from: _directorys_1.default.sectionsRoot,
                to: _directorys_1.default.distSectionsRoot,
                name: 'Sections',
            },
            {
                from: _directorys_1.default.snippetsRoot,
                to: _directorys_1.default.distSnippetsRoot,
                name: 'Snippets',
            },
            {
                from: _directorys_1.default.templatesRoot,
                to: _directorys_1.default.distTemplatesRoot,
                name: 'Templates',
            },
            {
                from: _directorys_1.default.customersRoot,
                to: _directorys_1.default.distCustomersRoot,
                name: 'Customers',
            }
        ];
        const stepsToRun = [removeDistDirectory, liveReload_1.removeLiveReload, buildDistDirectory];
        try {
            // run the steps for building the dist directory.
            for (var stepsToRun_1 = __asyncValues(stepsToRun), stepsToRun_1_1; stepsToRun_1_1 = yield stepsToRun_1.next(), !stepsToRun_1_1.done;) {
                const step = stepsToRun_1_1.value;
                yield step();
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (stepsToRun_1_1 && !stepsToRun_1_1.done && (_b = stepsToRun_1.return)) yield _b.call(stepsToRun_1);
            }
            finally { if (e_1) throw e_1.error; }
        }
        try {
            // start copying all directories from the above array to the dist folder.
            for (var directoriesToCopy_1 = __asyncValues(directoriesToCopy), directoriesToCopy_1_1; directoriesToCopy_1_1 = yield directoriesToCopy_1.next(), !directoriesToCopy_1_1.done;) {
                const directory = directoriesToCopy_1_1.value;
                yield copyToDist(directory.from, directory.to, directory.name);
            }
        }
        catch (e_2_1) { e_2 = { error: e_2_1 }; }
        finally {
            try {
                if (directoriesToCopy_1_1 && !directoriesToCopy_1_1.done && (_c = directoriesToCopy_1.return)) yield _c.call(directoriesToCopy_1);
            }
            finally { if (e_2) throw e_2.error; }
        }
        spinner.succeed('Finished building distribution folder');
        // sleep func called to start the webpack spinner.
        yield (0, _sleep_1.default)(500);
        yield runWebpackBuild();
        return;
    }
    catch (err) {
        spinner.fail('Error building distribution folder');
        return console.error(err);
    }
});
exports.default = buildDistFiles;
