class MRMBEDKZSELECTOR{
  constructor(el, AjaxRequestClass){
    this._rootEl = el;
    this._AjaxRequestClass = AjaxRequestClass;
    this._fetchCodeNrs();
    this._createTabsView();
    this._createTreeView();
    this._createSearchView();
    this._createResultView();
    this._createLoaderView();

    this._vdom = {};
    this._idSuffix = '__mrm_be_dkz_pagetreeview__';

    this.sendBranchRequest({branch: "root"});
    this.updateResults();
  }

  _createLoaderView(){
    this._$loader = document.createElement("div");
    this._$loader.classList.add("mrm_be_dkz_loader");
    this._$loader.innerHTML = `<strong>loading</strong><div class="loadingio-spinner-ellipsis"><div class="ldio"><div></div><div></div><div></div><div></div><div></div></div></div>`;
    this._rootEl.parentNode.insertBefore(this._$loader, this._rootEl);
  }
  _createResultView(){
    this._$resultView = document.createElement('div');
    this._$resultView.classList.add('mrm_be_dkz_pagetree_result_holder');
    this._$resultView.innerHTML = `
<div class="selections">
  <strong>Selektionen: (<span></span>)</strong>
  <ul></ul>
</div>
<div class="sws">
  <strong>Ausgewählte Suchwörter: (<span></span>)</strong>
  <ul></ul>
</div>
`;
    this._rootEl.parentNode.insertBefore(this._$resultView, this._rootEl);
  }
  _createSearchView(){
    this._$searchView = document.createElement('div');
    this._$searchView.classList.add('mrm_be_dkz_search_holder');
    this._$searchView.classList.add('out');
    this._$searchView.innerHTML = `<div class="search-results"></div>`;
    let $searchForm = document.createElement('form');
    $searchForm.innerHTML = `<input id="searchQuery" placeholder="Bezeichnung" required><button type="submit">Suchen</button>`;
    let $results = this._$searchView.querySelectorAll(".search-results")[0];

    $searchForm.addEventListener('submit', (e) => {
      e.preventDefault();
      e.stopPropagation();
      this._$loader.classList.add("in");
      $results.innerHTML = '';

      let query = e.target.querySelectorAll('#searchQuery')[0].value;
      this.sendRequest(TYPO3.settings.ajaxUrls.mrm_be_dkz_search, {query})
        .then(response => {
          if(!response) return $par.innerHTML = 'Keine Ergebnisse';
          response.list.forEach((item, i) => {
            let x = new MRMBEDKZPageTreeView($results, item, this.handleCallbacks.bind(this), "search");
            if(this._codenrs.includes(item.codenr)) x.check();
          });
        })
        .finally(() => {
          this._$loader.classList.remove("in");
        })
    });

    this._$searchView.prepend($searchForm);
    this._rootEl.parentNode.insertBefore(this._$searchView, this._rootEl);
  }
  _createTreeView(){
    this._view = document.createElement("div");
    this._view.classList.add('mrm_be_dkz_pagetree_holder');
    this._rootEl.parentNode.insertBefore(this._view, this._rootEl);
  }
  _createTabsView(){
    this._$tabs = document.createElement("div");
    this._$tabs.classList.add('mrm_be_dkz_pagetree_tabs');
    [["tree", "Baum"], ["search", "Suche"]].forEach((item, i) => {
      let $tab = document.createElement("div");
      $tab.classList.add(item[0]);
      $tab.classList.add('tab');
      if(i == 0)
        $tab.classList.add('active');
      $tab.innerHTML = item[1];
      this._$tabs.append($tab);
      $tab.addEventListener("click", this._changeView.bind(this));
    });
    this._rootEl.parentNode.insertBefore(this._$tabs, this._rootEl);
  }

  _changeView(e){
    e.preventDefault();
    e.stopPropagation();

    let $target = e.target;
    this._$tabs.querySelectorAll(".tab").forEach((itm) => {
      itm.classList.remove("active");
      if(itm == $target) itm.classList.add("active");
    })
    if($target.classList.contains('search')){
      this._$searchView.classList.remove('out');
      this._view.classList.add('out');
      this._$searchView.querySelectorAll("input")[0].value = '';
      this._$searchView.querySelectorAll(".search-results")[0].innerHTML = '';
    }
    if($target.classList.contains('tree')){
      this._$searchView.classList.add('out');
      this._view.classList.remove('out');
    }
  }

  sendRequest(url, args){
    this._$loader.classList.add("in");
    return new this._AjaxRequestClass(url)
      .withQueryArguments(args)
      .get()
      .then(function(response){ return response.resolve() })
      .then(function(resolved){
        //console.log("response", resolved);
        let data = JSON.parse(resolved.data);
        if(!data.success) return null;
        return data.data;
      })
      .finally(() => {
        this._$loader.classList.remove("in");
      })
  }

  sendBranchRequest(args){
    return this.sendRequest(TYPO3.settings.ajaxUrls.mrm_be_dkz_branch, args)
      .then(data => this.refreshVDOM(data))
      .then((x) => this.runCheckerStatus())
      .catch(function(e){
        console.log("e", e);
      })
  }

  updateResults(){
    this.sendRequest(TYPO3.settings.ajaxUrls.mrm_be_dkz_lists, {codenrs: this._codenrs.join(',')})
      .then(response => {
        if(!response) response = {};
        if(!response.berufe) response.berufe = [];
        if(!response.sws) response.sws = [];
        let $ulSelections = this._$resultView.querySelectorAll('.selections ul')[0];
        if($ulSelections){
          $ulSelections.innerHTML = '';
          if(response.berufe.length > 0){
            response.berufe.forEach(b => { $ulSelections.innerHTML += `<li><strong>${b.codenr}:</strong>&nbsp;${b.bezeichnung}</li>` });
          }
          let $spanSelections = this._$resultView.querySelectorAll('.selections strong span')[0];
          if($spanSelections){
            $spanSelections.innerHTML = response.berufe.length;
          }
        }
        let $ulSws = this._$resultView.querySelectorAll('.sws ul')[0];
        if($ulSws){
          $ulSws.innerHTML = '';
          if(response.sws.length > 0){
            response.sws.forEach(b => { $ulSws.innerHTML += `<li>${b}</li>` });
          }
          let $spanSws = this._$resultView.querySelectorAll('.sws strong span')[0];
          if($spanSws){
            $spanSws.innerHTML = response.sws.length;
          }
        }
      })
    ;
  }

  getView(){ return this._view }

  _fetchCodeNrs(){
    this._codenrs = this._rootEl.value.trim(" ,").split(",");
    this._codenrs.forEach(nr => { nr = nr.trim(); });
  }

  _generateId(nr){
    let _id = nr.split(" ").join("");
    let hash = 0, i, chr;
    for (i = 0; i < _id.length; i++) {
      chr   = _id.charCodeAt(i);
      hash  = ((hash << 5) - hash) + chr;
      hash |= 0; // Convert to 32bit integer
    }
    return `${this._idSuffix}${hash}`;
  }

  refreshVDOM(data) {
    data.list.forEach(itm => {
      let _id = this._generateId(itm.codenr);
      let parentId = itm.obercodenr ? this._generateId(itm.obercodenr) : null;
      let parent = parentId ? this._vdom[parentId] : null;

      if(!this._vdom[_id]){
        this._vdom[_id] = new MRMBEDKZPageTreeView((parent || this).getView(), itm, this.handleCallbacks.bind(this));
      }
    });

    //console.log(this._vdom);
    return true;
  }

  handleCallbacks(msg, data){
    //console.log("hcb", msg, data);
    switch(msg){
      case "codenr_add":
        this._codenrs.push(data.data);
        this.updateResults();
        break;
      case "codenr_remove":
        let index = this._codenrs.indexOf(data.data);
        this._codenrs.splice(index, 1);
        this.updateResults();
        break;
      case "codenr_toggle":
        let elementId = this._generateId(data.data.codenr);
        let element = this._vdom[elementId];
        if(data.data.fetch && (!element || (!element.hasItems() && element.isCollapsible())))
          this.sendBranchRequest({branch: data.data.codenr});
        break;
    }
    this._rootEl.value = this._codenrs.join(",");
  }

  runCheckerStatus(){
    this._codenrs.forEach(nr => {
      let _id = this._generateId(nr);
      if(this._vdom[_id]) this._vdom[_id].check();
    });
  }
}

class MRMBEDKZPageTreeView{
  constructor(parentView, rootData, callback, type = "tree"){
    this._callback = callback;
    this._$parentView = parentView;
    this._$el = null;
    this._isChecked = false;
    this._$checker = null;
    this._$detail = null;
    this._rootData = rootData;
    this._type = type;
    this._render();
  }

  check(status = true, emitCallback = false){
    if(!this._$checker) return;
    this._isChecked = status;
    let whattodo = status ? "add" : "remove";
    this._$checker.classList[whattodo]("checked");
    if(emitCallback)
      this._callback(`codenr_${whattodo}`, {data: this._rootData.codenr, type: this._type});
  }

  _render(){
    const collapsible = this._type == "tree" && this._rootData.codenr.indexOf('-') == -1;
    const _id = `mrm_be_dkz_pagetree_item-${this._rootData.codenr.split(" ").join("_")}`;
    let $itm = document.createElement("div");

    let $checker = document.createElement("a");
    $checker.innerHTML = `<span class="no">❌</span><span class="yes">✅</span>`;
    $checker.setAttribute("href", "#");
    $checker.classList.add("itm-checker");
    this.check(this._isChecked);
    $checker.addEventListener("click", (e) => {
      e.preventDefault();
      e.stopPropagation();
      this.check(!this._isChecked, true);
    });

    let $text = document.createElement("span");
    $text.innerHTML = `<strong>${this._rootData.codenr}:</strong> ${this._rootData.bezeichnung} (${this._rootData.swcount} SWs)`;
    $itm.setAttribute("id", _id);

    if(collapsible){
      let $detail = document.createElement("details");
      let $summary = document.createElement("summary");
      $summary.append($checker);
      $summary.append($text);
      $detail.append($summary);
      $itm.append($detail);

      $detail.addEventListener('click', e => {
        e.preventDefault();
        e.stopPropagation();
        $detail.open = !$detail.open;
        this._callback(`codenr_toggle`, {data: {codenr: this._rootData.codenr, fetch: $detail.open}, type: this._type});
      });
      this._$detail = $detail;
    }
    else{
      $itm.classList.add("not-collapsible");
      $itm.append($checker);
      $itm.append($text);
    }
    this._$parentView.append($itm);
    this._$checker = $checker;
    this._$el = $itm;
  }

  hasItems(){ return this._$detail != null && this._$detail.querySelectorAll('div').length > 0; }
  isCollapsible(){  return !this._$el.classList.contains("not-collapsible"); }
  getView(){ return this._$detail ? this._$detail : this._$el; }
  getRootData(){ return this._rootData; }
}

require(['TYPO3/CMS/Core/DocumentService'], function (DocumentService) {
  DocumentService.ready().then(() => {
    var el = document.getElementById(window.dkzFormElementId);
    if(!el) return;

    require(['TYPO3/CMS/Core/Ajax/AjaxRequest'], function (AjaxRequest) {
      new MRMBEDKZSELECTOR(el, AjaxRequest);
    });
  });
});
