import { getjQuery, onDOMContentLoaded } from '../mdb/util/index';
import EventHandler from '../mdb/dom/event-handler';
import SelectorEngine from '../mdb/dom/selector-engine';
import Manipulator from '../mdb/dom/manipulator';
import BSScrollSpy from '../bootstrap/mdb-prefix/scrollspy';

/**
 * ------------------------------------------------------------------------
 * Constants
 * ------------------------------------------------------------------------
 */

const NAME = 'scrollspy';
const DATA_KEY = `mdb.${NAME}`;
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';

const EVENT_ACTIVATE_BS = 'activate.bs.scrollspy';
const EVENT_ACTIVATE = `activate${EVENT_KEY}`;
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;

const CLASS_COLLAPSIBLE = 'collapsible-scrollspy';
const CLASS_ACTIVE = 'active';

const SELECTOR_LIST = 'ul';
const SELECTOR_DATA_SPY = '[data-mdb-spy="scroll"]';
const SELECTOR_ACTIVE = `.${CLASS_ACTIVE}`;
const SELECTOR_COLLAPSIBLE_SCROLLSPY = `.${CLASS_COLLAPSIBLE}`;

class ScrollSpy extends BSScrollSpy {
  constructor(element, data) {
    super(element, data);

    this._collapsibles = [];
    this._init();
  }

  dispose() {
    EventHandler.off(this._scrollElement, EVENT_ACTIVATE_BS);

    super.dispose();
  }

  // Getters
  static get NAME() {
    return NAME;
  }

  // Private
  _init() {
    this._bindActivateEvent();
    this._getCollapsibles();

    if (this._collapsibles.length === 0) {
      return;
    }

    this._showSubsection();
    this._hideSubsection();
  }

  _getHeight(element) {
    return element.offsetHeight;
  }

  _hide(target) {
    const itemsToHide = SelectorEngine.findOne(SELECTOR_LIST, target.parentNode);
    itemsToHide.style.overflow = 'hidden';
    itemsToHide.style.height = `${0}px`;
  }

  _show(target, destinedHeight) {
    target.style.height = destinedHeight;
  }

  _getCollapsibles() {
    const collapsibleElements = SelectorEngine.find(SELECTOR_COLLAPSIBLE_SCROLLSPY);

    if (!collapsibleElements) {
      return;
    }

    collapsibleElements.forEach((collapsibleElement) => {
      const listParent = collapsibleElement.parentNode;
      const list = SelectorEngine.findOne(SELECTOR_LIST, listParent);
      const listHeight = list.offsetHeight;
      this._collapsibles.push({
        element: list,
        relatedTarget: collapsibleElement.getAttribute('href'),
        height: `${listHeight}px`,
      });
    });
  }

  _showSubsection() {
    const activeElements = SelectorEngine.find(SELECTOR_ACTIVE);
    const actives = activeElements.filter((active) => {
      return Manipulator.hasClass(active, CLASS_COLLAPSIBLE);
    });

    actives.forEach((active) => {
      const list = SelectorEngine.findOne(SELECTOR_LIST, active.parentNode);
      const height = this._collapsibles.find((collapsible) => {
        return (collapsible.relatedTarget = active.getAttribute('href'));
      }).height;
      this._show(list, height);
    });
  }

  _hideSubsection() {
    const unactives = SelectorEngine.find(SELECTOR_COLLAPSIBLE_SCROLLSPY).filter((collapsible) => {
      return Manipulator.hasClass(collapsible, 'active') === false;
    });
    unactives.forEach((unactive) => {
      this._hide(unactive);
    });
  }

  _bindActivateEvent() {
    EventHandler.on(this._element, EVENT_ACTIVATE_BS, (e) => {
      this._showSubsection();
      this._hideSubsection();
      EventHandler.trigger(this._element, EVENT_ACTIVATE, {
        relatedTarget: e.relatedTarget,
      });
    });
  }
}

/**
 * ------------------------------------------------------------------------
 * Data Api implementation - auto initialization
 * ------------------------------------------------------------------------
 */

EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
  SelectorEngine.find(SELECTOR_DATA_SPY).forEach((el) => {
    let instance = ScrollSpy.getInstance(el);
    if (!instance) {
      instance = new ScrollSpy(el, Manipulator.getDataAttributes(el));
    }
  });
});

/**
 * ------------------------------------------------------------------------
 * jQuery
 * ------------------------------------------------------------------------
 * add .rating to jQuery only if jQuery is present
 */

onDOMContentLoaded(() => {
  const $ = getjQuery();

  if ($) {
    const JQUERY_NO_CONFLICT = $.fn[NAME];
    $.fn[NAME] = ScrollSpy.jQueryInterface;
    $.fn[NAME].Constructor = ScrollSpy;
    $.fn[NAME].noConflict = () => {
      $.fn[NAME] = JQUERY_NO_CONFLICT;
      return ScrollSpy.jQueryInterface;
    };
  }
});

export default ScrollSpy;
