import {toggle} from '#core/dom/style';

import {dev, user, userAssert} from '#utils/log';

import {handleAutoscroll} from './autoscroll';

/**
 * Class representing toolbar behavior in sidebar
 * @throws User error if element with id [toolbar-target] isn't found in DOM.
 */
export class Toolbar {
  /**
   * @param {!Element} element
   * @param {!AMP.BaseElement} contextElement
   */
  constructor(element, contextElement) {
    /** @private @const {!AMP.BaseElement} */
    this.context_ = contextElement;

    /** @private {!Element} */
    this.toolbarDomElement_ = element;

    /** @const @private {!../../../src/service/ampdoc-impl.AmpDoc} */
    this.ampdoc_ = contextElement.getAmpDoc();

    /** @private {string} */
    this.toolbarMedia_ = this.toolbarDomElement_.getAttribute('toolbar');

    /** @private {?Element} */
    this.toolbarClone_ = null;

    /** @private {Element|undefined} */
    this.toolbarTarget_ = undefined;

    /** @private {boolean} */
    this.toolbarShown_ = false;

    // Default to toolbar target being hidden
    this.toolbarDomElement_.classList.add('amp-sidebar-toolbar-target-hidden');

    this.buildCallback_();
  }

  /**
   * Function called to check if we should show or hide the toolbar
   */
  onLayoutChange() {
    // Get if we match the current toolbar media
    const matchesMedia = this.ampdoc_.win.matchMedia(
      this.toolbarMedia_
    ).matches;

    // Remove and add the toolbar dynamically
    if (matchesMedia) {
      this.attemptShow_();
    } else {
      this.hideToolbar_();
    }
  }

  /**
   * Private function to build the DOM element for the toolbar
   * @private
   */
  buildCallback_() {
    this.toolbarClone_ = this.toolbarDomElement_.cloneNode(true);
    const targetId = userAssert(
      this.toolbarDomElement_.getAttribute('toolbar-target'),
      '"toolbar-target" is required',
      this.toolbarDomElement_
    );
    // Set the target element to the toolbar clone if it exists.
    const targetElement = this.ampdoc_.getElementById(targetId);
    if (targetElement) {
      this.toolbarTarget_ = targetElement;
      this.toolbarClone_.classList.add('i-amphtml-toolbar');
      toggle(this.toolbarTarget_, false);
    } else {
      // This error will be caught and the side bar will continue to function
      // without the toolbar feature.
      throw user().createError(
        `Could not find the toolbar-target element with an id: ${targetId}`
      );
    }
  }

  /**
   * Returns if the sidebar is currently in toolbar media query
   * @return {boolean}
   * @private
   */
  isToolbarShown_() {
    return this.toolbarShown_;
  }

  /**
   * Function to attempt to show the toolbar,
   * and hide toolbar-only element in the sidebar.
   * @return {Promise}
   * @private
   */
  attemptShow_() {
    if (this.isToolbarShown_()) {
      return Promise.resolve();
    }

    // Display the elements
    return this.context_.mutateElement(() => {
      if (this.toolbarTarget_) {
        toggle(this.toolbarTarget_, true);
        if (!this.toolbarTarget_.contains(this.toolbarClone_)) {
          this.toolbarTarget_.appendChild(this.toolbarClone_);
        }
        this.toolbarDomElement_.classList.add(
          'amp-sidebar-toolbar-target-shown'
        );
        this.toolbarDomElement_.classList.remove(
          'amp-sidebar-toolbar-target-hidden'
        );
        this.toolbarShown_ = true;

        handleAutoscroll(this.ampdoc_, dev().assertElement(this.toolbarClone_));
      }
    });
  }

  /**
   * Function to hide the toolbar,
   * and show toolbar-only element in the sidebar.
   * @private
   */
  hideToolbar_() {
    if (!this.isToolbarShown_()) {
      return;
    }

    this.context_.mutateElement(() => {
      // Hide the elements
      if (this.toolbarTarget_) {
        toggle(this.toolbarTarget_, false);
        this.toolbarDomElement_.classList.add(
          'amp-sidebar-toolbar-target-hidden'
        );
        this.toolbarDomElement_.classList.remove(
          'amp-sidebar-toolbar-target-shown'
        );
        this.toolbarShown_ = false;
      }
    });
  }
}
