var MochaEngine = Namespace.declare("org",
  class MochaEngine extends UcpComponent {
    static start() {
      console.log(this.name + " is ready");
      UcpComponentSupport.importLink(this.IOR.loader.basePath + "/src/css/mocha.css", "stylesheet", "text/css");
    }

    static dependencies() {
      return [
        "/EAMD.ucp/Components/org/MochaEngine/4.0.1/MochaEngine.component.xml",
        this.IOR.loader.basePath + "/src/js/chai.js",
        this.IOR.loader.basePath + "/src/js/mocha.js"
      ];
    }

    constructor() {
      super();
      this.components = {} ;
    }

    init() {
      if (this.isInitialized) {
        return;
      }
      super.init();

      return this;
    }

    add(component) {
      super.add(component);
    }

    updateView(view) {
      if (!this._private.initializedMocha && document.getElementById(view.viewId)) {
        this.DOMReady();
      }

      if (this.regression) {
        console.log("starting Tests immediatly");
      }
    }

    DOMReady() {
      if(this._private.initializedMocha) {
        return;
      }
      mocha.setup('bdd');
      const {expect} = chai;
      window.expect = expect;
      document.getElementById(this.viewId).addEventListener('drop', this.onDrop.bind(this), false);

      this._private.initializedMocha = true;
    }

    onBeingAdded() {
      this.DOMReady();
    }

    onDrop(event) {
      event.preventDefault();
      event.stopPropagation();
      if (!event instanceof DragEvent) {
        return;
      }
      const url = event.dataTransfer.getData("URL");

      if (!url) {
        this.addError('dropped url is not defined');
        return;
      }
      try {
        this.loadAndRunDroppedTest(url);
      } catch (error) {
        console.error(error);
      }
    }

    async loadAndRunDroppedTest(url) {
      const aClass = await this.loadDescriptor(url);
      if (!aClass) {
        this.addError(`error loading ${url}`);
        return;
      }

      const arr = url.split(/\//);
      arr.pop();
      arr.push('test');
      arr.push('js');
      arr.push(`${aClass.name}MochaTest.js`);
      url = arr.join('/');

      await this.loadTest(url);
      this.runTest();
    }

    loadTest(url) {
      return new Promise((resolve, reject) => {
        let script = document.getElementById(url);
        if (script) {
          script.remove();
        }
        script = document.createElement('script');
        script.type = 'module';
        script.src = url;
        script.id = url;
        script.setAttribute('data-id', 'mocha');
        script.onload = () => resolve();
        script.onerror = () => reject();
        document.head.append(script);
      });
    }

    runTest() {
      mocha.run();
    }

    async loadDescriptor(descriptorUrl) {
      let aClass = ONCE.lookupClass4Descriptor(descriptorUrl);
      if (aClass) {
        return aClass;
      }

      const ior = new IOR().init(descriptorUrl);
      aClass = await ONCE.start(ior);
      if (!aClass) {
        return undefined;
      }
      console.debug("loaded ", aClass.type.name);
      return aClass;
    }

    addError(error) {
      // @todo replace with content name
      const div = document.getElementById(this.viewId);
      div.classList.add('alert-danger');
      div.innerHTML += `<p>${error}</p>`;
    }

    async scan() {
      const ucpComponents = await Structr.find("UcpComponentDescriptor");
      if (!ucpComponents || ucpComponents.length === 0) {
        console.log("no ucp components");
        return;
      }
      this.components = {};

      ucpComponents.forEach(comp => {
        if (!comp.model) {
          console.warn(comp);
          return;
        }
        const name = comp.name;
        const lVersion = (comp.model.version !== null) ? comp.model.version.name : null;
        if (!lVersion) {
          console.warn(`component ${name} has no version`);
          return;
        }
        if (
          comp.model.path.indexOf("org/demos") < 0 &&
          comp.model.path.indexOf("org/playground") < 0 &&
          comp.model.path.indexOf("org/playgound") < 0
        ) {
          const realName = name.replace(/\.component\.xml$/, '');
          this.components[realName] = this.components[realName] || {};

          const arr = comp.model.path.split(/\//);
          arr.pop();
          arr.push('test');
          arr.push('js');
          arr.push(`${realName}MochaTest.js`);

          this.components[realName][lVersion] = {
            href: comp.model.path,
            test: arr.join('/'),
            errors: [],
          };
        }
      });

    }

    checkDescriptorExists(realName, version) {
      const {href} = this.components[realName][version];
      return this.linkExists(`${href}`)
        .then(exists => {
          if (!exists) {
            this.components[realName][version].errors.push('descriptor');
          }
        });
    }

    checkTestExists(realName, version) {
      const {test} = this.components[realName][version];
      return this.linkExists(`${test}`)
        .then(exists => {
          if (!exists) {
            this.components[realName][version].errors.push('testClass');
          }
        });
    }

    linkExists(link) {
      const salt = new Date().getTime();
      link += link.indexOf('?') >= 0 ? '&' : '?';
      link += `nocache=${salt}`;
      return new Promise(resolve => {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", link);

        xhr.onload = () => {
          resolve(xhr.status === 200);
        };
        xhr.onerror = () => resolve(false);
        xhr.send();
      });
    }

  }
);