import { Util } from '../util/Util';
import { DialogsBaseCtrl, DialogsWaitCtrl, DialogsConfirmCtrl, DialogsConfirmDeletionCtrl } from '../Controller/Controller.module';
import { DialogsConfirmDeletionTemplate, DialogsConfirmTemplate, DialogsBaseTemplate, DialogsWaitTemplate } from '../Template/Template.module';

let StDialogsServiceInject = ['StDialogsDefaults', '$uibModal', '$templateCache', '$uibModalStack', '$window', '$timeout'];
export class StDialogsService {
    static get $inject(){
        return StDialogsServiceInject;
    }
    constructor(...injectables){
        Util.injectNg(injectables, StDialogsServiceInject, this);
    }
    mergeConfig(config, type){
        if (!type) type = 'dialogs';
        if (!angular.isObject(config)) config = {};
        return angular.merge({}, this.StDialogsDefaults[type], config);
    }
    getBaseConfig(config, template, controller, data){
        let resolve = {};
        if (angular.isObject(data)) {
            angular.forEach(data, (value, key) => {
                resolve[key] = () => value;
            });
        } else {
            resolve = {
                data: () => data
            }
        }

        let options = {
            controller,
            controllerAs: '$ctrl',
            resolve
        };
        if (template.isUrl)options.templateUrl = template.template;
        else options.template = template.template;
        return Object.assign({}, config, options);
    }
    _applyRendered(modal, config){
        if (config.rendered) {
            if (angular.isFunction(config.rendered)) {
                config.rendered.apply(config.rendered.this, config.rendered.values);
            } else if (isPlainObject(config.rendered)) {
                let { rendered } = config;
                modal.rendered.then(() => {
                    let el = this.$uibModalStack.getTop().value.modalDomEl,
                    selected = angular.element(el[0].querySelectorAll(rendered.selector));
                    if (rendered.apply in selected) {
                        selected[rendered.apply].apply(selected, rendered.values);
                    }
                })
            }
        };
        return modal;
    }
    error(header, msg, config, data = {}){
        config = this.mergeConfig(config);
        let resolve = {
            texts: {
                header: angular.copy(header),
                msg: angular.copy(msg),
            },
            data: config.copy ? angular.copy(data) : data,
            classes: {
                header: 'dialog-header-error',
                text: 'danger',
                icon: config.icon || 'fas fa-exclamation-triangle',
                btnClose: 'btn-danger'
            },
            btnText: {
                close: 'DIALOGS_CLOSE'
            }
        }
        return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, {template: DialogsBaseTemplate}, DialogsBaseCtrl, resolve)), config);
    }
    wait(header, msg, progressInfo, config){
        config = this.mergeConfig(config);
        let resolve = {
            texts: {
                header: angular.copy(header),
                msg: angular.copy(msg),
            },
            progressInfo,
            classes: {
                header: 'dialog-header-wait',
                icon: config.icon || 'fas fa-clock'
            }
        }
        return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, {template: DialogsWaitTemplate}, DialogsWaitCtrl, resolve)), config);
    }
    notify(header, msg, config, data = {}){
        config = this.mergeConfig(config);
        let resolve = {
            texts: {
                header: angular.copy(header),
                msg: angular.copy(msg),
            },
            data: config.copy ? angular.copy(data) : data,
            classes: {
                header: 'dialog-header-notify',
                text: 'info',
                icon: config.icon || 'fas fa-info-circle',
                btnClose: 'btn-primary'
            },
            btnText: {
                close: 'DIALOGS_OK'
            }
        }
        return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, {template: DialogsBaseTemplate}, DialogsBaseCtrl, resolve)), config);
    }
    success(header, msg, config, data = {}){
        config = this.mergeConfig(config);
        let resolve = {
            texts: {
                header: angular.copy(header),
                msg: angular.copy(msg),
            },
            data: config.copy ? angular.copy(data) : data,
            classes: {
                header: 'dialog-header-success',
                text: 'success',
                icon: config.icon || 'fas fa-check-circle',
                btnClose: 'btn-success'
            },
            btnText: {
                close: 'DIALOGS_CLOSE'
            }
        }
        return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, {template: DialogsBaseTemplate}, DialogsBaseCtrl, resolve)), config);
    }
    infoModule(header, msg, config, data = {}){
        config = this.mergeConfig(config);
        let resolve = {
            texts: {
                header: angular.copy(header),
                msg: angular.copy(msg),
            },
            data: config.copy ? angular.copy(data) : data,
            classes: {
                header: 'dialog-header-notify',
                text: 'dark',
                icon: config.icon || 'fas fa-info-circle',
                btnClose: 'btn-primary'
            },
            btnText: {
                close: 'DIALOGS_CLOSE'
            }
        }
        return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, {template: DialogsBaseTemplate}, DialogsBaseCtrl, resolve)), config);
    }
    confirm(header, msg, config, data = {}){
        config = this.mergeConfig(config);
        let resolve = {
            texts: {
                header: angular.copy(header),
                msg: angular.copy(msg),
            },
            data: config.copy ? angular.copy(data) : data,
            classes: {
                header: 'dialog-header-confirm',
                icon: config.icon || 'fas fa-question-circle',
                btnClose: 'btn-default',
                btnAccept: 'btn-primary'
            },
            btnText: {
                accept: 'DIALOGS_YES',
                close: 'DIALOGS_NO'
            }
        }
        return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, {template: DialogsConfirmTemplate}, DialogsConfirmCtrl, resolve)), config);
    }
    confirmDeletion(data, config = {}, options = {}){
        options = this.mergeConfig(options);
        if (!isPlainObject(config)) config = {};
        let resolve = {data, config},
        template = {};
        if (!config.templateUrl) template = {template: DialogsConfirmDeletionTemplate}
        else template = {template: config.templateUrl, isUrl: true}
        let base = this.getBaseConfig(options, template, DialogsConfirmDeletionCtrl, resolve);
        return this._applyRendered(this.$uibModal.open(base), config);
    }
    create(config, data, options){
        options = this.mergeConfig(options);
        if (angular.isString(config)) {
            config = {
                component: config
            }
        } else if (!isPlainObject(config)) throw new Error('Needs to be an Object | string');
        else if (!(config.template || config.templateUrl || config.controller || config.component)) throw new Error('Needs a component or controller/template');
        let modalOptions = Object.assign({}, options, config, {
            resolve: {
                data: () => config.copy ? angular.copy(data) : data
            }
        });
        return this._applyRendered(this.$uibModal.open(modalOptions), config);
    }
}