"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const path = require("path");
const util_1 = require("util");
const less = require("less");
const os = require("os");
const interfaces_1 = require("./interfaces");
const utils_1 = require("../utils");
const CompressCssCompiler_1 = require("./CompressCssCompiler");
const LessPlugins_1 = require("../model/LessPlugins");
class LessCompiler {
    constructor(pluginName, dependencyPaths, assetsPath, mainRepoDir, isProduction) {
        this.pluginName = pluginName;
        this.dependencyPaths = dependencyPaths;
        this.assetsPath = assetsPath;
        this.mainRepoDir = mainRepoDir;
        this.isProduction = isProduction;
        this.pathToEntryFile = '';
        this.pathToLessSources = path.join(this.assetsPath, LessCompiler.LESS_SOURCES_DIR);
        for (const name of ['plugin', 'cplace']) {
            const pathToEntryFile = path.join(this.pathToLessSources, `${name}.less`);
            if (fs.existsSync(pathToEntryFile)) {
                this.pathToEntryFile = pathToEntryFile;
                break;
            }
        }
        if (!this.pathToEntryFile) {
            throw Error(`[${this.pluginName}] cannot determine path to LESS entry file`);
        }
    }
    compile() {
        const filename = path.basename(this.pathToEntryFile, '.less');
        const entryFile = path.join(this.assetsPath, LessCompiler.LESS_SOURCES_DIR, `${filename}.less`);
        const lessOutputDir = CompressCssCompiler_1.CompressCssCompiler.getCssOutputDir(this.assetsPath);
        const outputFile = path.join(lessOutputDir, `${filename}.css`);
        const sourceMapFile = path.join(lessOutputDir, `${filename}.css.map`);
        const writeFile = util_1.promisify(fs.writeFile);
        const start = new Date().getTime();
        console.log(`⟲ [${this.pluginName}] starting LESS compilation...`);
        return new Promise((resolve, reject) => {
            const lesscOptions = {
                filename: path.resolve(entryFile),
                plugins: LessPlugins_1.lessPlugins(this.pluginName)
            };
            if (!this.isProduction) {
                lesscOptions.sourceMap = {
                    sourceMapBasepath: path.join(this.assetsPath, LessCompiler.LESS_SOURCES_DIR),
                    sourceMapRootpath: `../${LessCompiler.LESS_SOURCES_DIR}/`,
                    sourceMapURL: `${filename}.css.map`
                };
            }
            let lessContent = fs.readFileSync(entryFile, 'utf8');
            this.appendGlobalCSSVariables(lessContent, lesscOptions)
                .then((preParsedLessContent) => {
                less
                    .render(preParsedLessContent, lesscOptions)
                    .catch((err) => {
                    console.error(utils_1.cerr `${err}`);
                    throw Error(`[${this.pluginName}] LESS compilation failed`);
                })
                    .then((output) => {
                    let end = new Date().getTime();
                    console.log(utils_1.cgreen `⇢`, `[${this.pluginName}] LESS compiled, writing output... (${utils_1.formatDuration(end - start)})`);
                    if (!fs.existsSync(lessOutputDir)) {
                        fs.mkdirSync(lessOutputDir);
                    }
                    const promises = [
                        writeFile(outputFile, output.css, 'utf8')
                    ];
                    if (!this.isProduction) {
                        promises.push(writeFile(sourceMapFile, output.map, 'utf8'));
                    }
                    return Promise
                        .all(promises)
                        .then(() => {
                        let end = new Date().getTime();
                        console.log(utils_1.GREEN_CHECK, `[${this.pluginName}] LESS finished (${utils_1.formatDuration(end - start)})`);
                        resolve(interfaces_1.CompilationResult.CHANGED);
                    })
                        .catch((err) => {
                        console.error(utils_1.cerr `${err}`);
                        throw Error(`[${this.pluginName}] Failed to write LESS output`);
                    });
                })
                    .catch((e) => reject(e));
            })
                .catch((e) => reject(e));
        });
    }
    appendGlobalCSSVariables(lessContent, lesscOptions) {
        const content = lessContent;
        return new Promise((res) => {
            less['parse'](content, lesscOptions, (err, root, _imports, _options) => {
                if (err) {
                    throw Error('Unable to pre-parse global css variables');
                }
                else {
                    res(this.parseLESSVariablesToCSS(content, root._variables));
                }
            });
        });
    }
    parseLESSVariablesToCSS(lessContent, lessVariables = {}) {
        let newContent = lessContent;
        const lessVars = Object.keys(lessVariables || {});
        if (lessVars.length) {
            const variables = lessVars.map((it) => {
                const key = it.replace('@', '');
                return `--${key}:${it};`;
            });
            newContent = `
                ${newContent}
                
                :root {
                    ${variables.join(os.EOL)}
                }
            `;
        }
        return newContent;
    }
}
LessCompiler.LESS_SOURCES_DIR = 'less';
exports.LessCompiler = LessCompiler;
//# sourceMappingURL=LessCompiler.js.map