import { Loading } from 'vant';
import './index.styl'

export default () => {
  return {
    install(Vue,{http,component = Loading}){
      
      function removeMiddleHttp(target,handles) {
        const index = handles.findIndex(handle => handle === target);
        if(index >= 0){
          handles.splice(index,1);
        }
      }
      
      class GlobalLoading {
        constructor(el){
          this.el = el;
        }
        get loading(){
          return this.el._loading;
        }
        set loading(val){
          this.el._loading = val;
          if(val){
            this.el.setAttribute('disabled', 'disabled')
            removeMiddleHttp(this.el._httpResponseHandle_,http.interceptors.response.handlers);
          }else {
            this.el.removeAttribute('disabled')
            removeMiddleHttp(this.el._httpRequestHandle_,http.interceptors.request.handlers);
          }
        }
        show(){
          this.loading = true;
          Vue.prototype.$emit('global:INTERFACE_ACTION',{error_no:'1'})
        }
        hide(){
          this.loading = false;
          Vue.prototype.$emit('global:INTERFACE_ACTION',{error_no:'2'})
        }
      }

      class ChildLoading extends GlobalLoading{
        constructor(el,component){
          super(...arguments)
          this.loadCom = component
        }
        show () {
          this.loading = true
          this.$el = document.createElement('div')
          this.$el.className = 'loadingAction'
          this.el.childNodes.length ? this.el.insertBefore(this.$el, this.el.childNodes[0]) : this.el.push(this.$el)
          this.$v = new Vue({
            render: h => h(this.loadCom)
          }).$mount(this.$el)
        }

        hide () {
          if (this.$v) {
            this.$v.$destroy()
            this.el.removeChild(this.el.childNodes[0])
            this.$v = null
          }
          this.loading = false
        }

      }

      Vue.directive('LoadingAction',{
        bind(el,binding){
          let action = binding.value;
          let loadCom = component;
          if(typeof action === 'object'){
            if(binding.value.action && typeof binding.value.action === 'function'){
              action = binding.value.action;
              loadCom = binding.value.component || loadCom;
            }else {
              return console.error('LoadingAction: action must be a Function that should return a Promise!');
            }
          }else if(typeof action !== 'function'){
            return console.error('LoadingAction: action must be a Function that should return a Promise!');
          }
          const glob = binding.modifiers.full ? new GlobalLoading(el) : new ChildLoading(el, loadCom);
          function run(){
            if(glob.loading){
              return;
            }
            http.interceptors.request.handlers.unshift(el._httpRequestHandle_ = {
              fulfilled(config){
                if(!el._loading){
                  glob.show();
                  config._loading_el_ = el;
                }
                return config;
              }
            })

            let request = new Promise(resolve => {
              el._timer = setTimeout(resolve,http.defaults.timeout || 6000);
            })

            http.interceptors.response.handlers.unshift(el._httpResponseHandle_ = {
              fulfilled(response){
                request.finally(()=>{
                  if(response.config._loading_el_ === el){
                    glob.hide();
                  }
                })
                return response
              },
              rejected(err){
                request.finally(()=>{
                  if(err.config._loading_el_ === el){
                    glob.hide();
                  }
                })
                return Promise.reject(err);
              }
            })

            const result = action();
            if(result){
              clearTimeout(el._timer);
              request = result;
            }
          }

          el.className += ' g-loading-action';
          if(binding.arg === 'autoInit'){
            run();
          }else {
            el.addEventListener('click',run)
          }
        }
      })
    }
  }
}