import Data from '../mdb/dom/data';
import EventHandler from '../mdb/dom/event-handler';
import Manipulator from '../mdb/dom/manipulator';
import SelectorEngine from '../mdb/dom/selector-engine';

import BSButton from '../bootstrap/mdb-prefix/button';
import { bindCallbackEventsIfNeeded } from '../autoinit/init';

const NAME = 'button';
const DATA_KEY = `mdb.${NAME}`;
const EVENT_KEY = `.${DATA_KEY}`;

const EVENT_CLICK = `click${EVENT_KEY}`;
const EVENT_TRANSITIONEND = 'transitionend';
const EVENT_MOUSEENTER = 'mouseenter';
const EVENT_MOUSELEAVE = 'mouseleave';
const EVENT_HIDE = `hide${EVENT_KEY}`;
const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
const EVENT_SHOW = `show${EVENT_KEY}`;
const EVENT_SHOWN = `shown${EVENT_KEY}`;

const CLASS_NAME_ACTIVE = 'active';
const CLASS_NAME_SHOWN = 'shown';
const CLASS_NAME_FIXED_ACTION_BTN = 'fixed-action-btn';

const SELECTOR_ACTION_BUTTON = '.fixed-action-btn:not(.smooth-scroll) > .btn-floating';
const SELECTOR_LIST_ELEMENT = 'ul .btn';
const SELECTOR_LIST = 'ul';

class Button extends BSButton {
  constructor(element) {
    super(element);
    this._fn = {};

    if (this._element) {
      Data.setData(this._element, DATA_KEY, this);
      this._init();
      Manipulator.setDataAttribute(this._element, `${this.constructor.NAME}-initialized`, true);
      bindCallbackEventsIfNeeded(this.constructor);
    }
  }

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

  static jQueryInterface(config, options) {
    return this.each(function () {
      let data = Data.getData(this, DATA_KEY);
      const _config = typeof config === 'object' && config;
      if (!data && /dispose/.test(config)) {
        return;
      }

      if (!data) {
        data = new Button(this, _config);
      }
      if (typeof config === 'string') {
        if (typeof data[config] === 'undefined') {
          throw new TypeError(`No method named "${config}"`);
        }
        data[config](options);
      }
    });
  }

  // Getters
  get _actionButton() {
    return SelectorEngine.findOne(SELECTOR_ACTION_BUTTON, this._element);
  }

  get _buttonListElements() {
    return SelectorEngine.find(SELECTOR_LIST_ELEMENT, this._element);
  }

  get _buttonList() {
    return SelectorEngine.findOne(SELECTOR_LIST, this._element);
  }

  get _isTouchDevice() {
    return 'ontouchstart' in document.documentElement;
  }

  // Public
  show() {
    if (Manipulator.hasClass(this._element, CLASS_NAME_FIXED_ACTION_BTN)) {
      EventHandler.off(this._buttonList, EVENT_TRANSITIONEND);
      EventHandler.trigger(this._element, EVENT_SHOW);
      // EventHandler.on(this._buttonList, EVENT_TRANSITIONEND, this._bindListOpenTransitionEnd);
      this._bindListOpenTransitionEnd();
      Manipulator.addStyle(this._element, { height: `${this._fullContainerHeight}px` });
      this._toggleVisibility(true);
    }
  }

  hide() {
    if (Manipulator.hasClass(this._element, CLASS_NAME_FIXED_ACTION_BTN)) {
      EventHandler.off(this._buttonList, EVENT_TRANSITIONEND);
      EventHandler.trigger(this._element, EVENT_HIDE);
      // EventHandler.on(this._buttonList, EVENT_TRANSITIONEND, this._bindListHideTransitionEnd);
      this._bindListHideTransitionEnd();
      this._toggleVisibility(false);
    }
  }

  dispose() {
    if (Manipulator.hasClass(this._element, CLASS_NAME_FIXED_ACTION_BTN)) {
      EventHandler.off(this._actionButton, EVENT_CLICK);
      this._actionButton.removeEventListener(EVENT_MOUSEENTER, this._fn.mouseenter);
      this._element.removeEventListener(EVENT_MOUSELEAVE, this._fn.mouseleave);
    }
    Manipulator.removeDataAttribute(this._element, `${this.constructor.NAME}-initialized`);

    super.dispose();
  }

  // Private
  _init() {
    if (Manipulator.hasClass(this._element, CLASS_NAME_FIXED_ACTION_BTN)) {
      this._saveInitialHeights();
      this._setInitialStyles();
      this._bindInitialEvents();
    }
  }

  _bindMouseEnter() {
    this._actionButton.addEventListener(
      EVENT_MOUSEENTER,
      // prettier-ignore
      this._fn.mouseenter = () => {
        if (!this._isTouchDevice) {
          this.show();
        }
      }
      // prettier-ignore
    );
  }

  _bindMouseLeave() {
    this._element.addEventListener(
      EVENT_MOUSELEAVE,
      // prettier-ignore
      this._fn.mouseleave = () => {
        this.hide();
      }
      // prettier-ignore
    );
  }

  _bindClick() {
    EventHandler.on(this._actionButton, EVENT_CLICK, () => {
      if (Manipulator.hasClass(this._element, CLASS_NAME_ACTIVE)) {
        this.hide();
      } else {
        this.show();
      }
    });
  }

  _bindListHideTransitionEnd() {
    EventHandler.on(this._buttonList, EVENT_TRANSITIONEND, (event) => {
      if (event.propertyName === 'transform') {
        EventHandler.off(this._buttonList, EVENT_TRANSITIONEND);
        this._element.style.height = `${this._initialContainerHeight}px`;
        EventHandler.trigger(this._element, EVENT_HIDDEN);
      }
    });
  }

  _bindListOpenTransitionEnd() {
    EventHandler.on(this._buttonList, EVENT_TRANSITIONEND, (event) => {
      if (event.propertyName === 'transform') {
        EventHandler.off(this._buttonList, EVENT_TRANSITIONEND);
        EventHandler.trigger(this._element, EVENT_SHOWN);
      }
    });
  }

  _toggleVisibility(isVisible) {
    const action = isVisible ? 'addClass' : 'removeClass';
    const listTranslate = isVisible ? 'translate(0)' : `translateY(${this._fullContainerHeight}px)`;
    Manipulator.addStyle(this._buttonList, { transform: listTranslate });

    if (this._buttonListElements) {
      this._buttonListElements.forEach((el) => Manipulator[action](el, CLASS_NAME_SHOWN));
    }
    Manipulator[action](this._element, CLASS_NAME_ACTIVE);
  }

  _getHeight(element) {
    const computed = window.getComputedStyle(element);
    const height = parseFloat(computed.getPropertyValue('height'));
    return height;
  }

  _saveInitialHeights() {
    this._initialContainerHeight = this._getHeight(this._element);
    this._initialListHeight = this._getHeight(this._buttonList);
    this._fullContainerHeight = this._initialContainerHeight + this._initialListHeight;
  }

  _bindInitialEvents() {
    this._bindClick();
    this._bindMouseEnter();
    this._bindMouseLeave();
  }

  _setInitialStyles() {
    this._buttonList.style.marginBottom = `${this._initialContainerHeight}px`;
    this._buttonList.style.transform = `translateY(${this._fullContainerHeight}px)`;

    this._element.style.height = `${this._initialContainerHeight}px`;
  }
}

export default Button;
