import ngModule from '../module';
import moduleImport from 'module-import';

factory.$inject = ['$http', '$window', '$ocLazyLoad', '$translatePartialLoader', '$translate', '$q'];
export function factory($http, $window, $ocLazyLoad, $translatePartialLoader, $translate, $q) {
    class ModuleLoader {
        constructor() {
            this._loaded = {};
        }
        load(moduleName, validations) {
            let moduleConf = $window.routes.find(i => i && i.module == moduleName);
            if (!moduleConf)
                return $q.reject(new Error(`Module not found: ${moduleName}`));

            let loaded = this._loaded;

            if (loaded[moduleName] === true)
                return Promise.resolve(true);
            if (loaded[moduleName] instanceof Promise)
                return loaded[moduleName];
            if (loaded[moduleName] === false)
                return Promise.resolve(true);

            loaded[moduleName] = false;

            let depPromises = [];
            let deps = moduleConf.dependencies;

            if (deps) {
                for (let dep of deps)
                    depPromises.push(this.load(dep, validations));
            }

            loaded[moduleName] = new Promise((resolve, reject) => {
                Promise.all(depPromises).then(() => {
                    let promises = [];

                    $translatePartialLoader.addPart(moduleName);
                    promises.push(new Promise(resolve => {
                        $translate.refresh().then(resolve, resolve);
                    }));

                    if (validations) {
                        promises.push(new Promise(resolve => {
                            $http.get(`/${moduleName}/api/modelInfo`).then(
                                json => this.onValidationsReady(json, resolve),
                                () => resolve()
                            );
                        }));
                    }

                    promises.push(moduleImport(moduleName));

                    Promise.all(promises).then(() => {
                        loaded[moduleName] = true;
                        resolve($ocLazyLoad.load({name: moduleName}));
                    }).catch(reject);
                }).catch(reject);
            });

            return loaded[moduleName];
        }
        onValidationsReady(json, resolve) {
            let entities = json.data;
            for (let entity in entities) {
                let fields = entities[entity].validations;
                for (let field in fields) {
                    let validations = fields[field];
                    for (let validation of validations)
                        this.parseValidation(validation);
                }
            }

            Object.assign($window.validations, json.data);
            resolve();
        }
        parseValidation(val) {
            switch (val.validation) {
            case 'custom':
                // TODO: Replace eval
                val.bindedFunction = eval(`(${val.bindedFunction})`);
                break;
            case 'format':
                val.with = new RegExp(val.with);
                break;
            }
        }
    }

    return new ModuleLoader();
}
ngModule.factory('vnModuleLoader', factory);