import {vlElement, define} from '/node_modules/vl-ui-core/dist/vl-core.js';

/**
 * Pager changed event
 * @event VlPager#change
 * @property {number} currentPage - Huidige pagina.
 * @property {number} totalPage - Totaal aantal paginas.
 * @property {number} itemsPerPage - Items per pagina.
 * @property {number} totalItems - Totaal aantal items.
 */

/**
 * VlPager
 * @class
 * @classdesc Gebruik de pager component om het aantal beschikbare pagina's weer te geven, markeer de huidige pagina en voeg navigatie knoppen toe.
 *
 * @extends HTMLElement
 * @mixes vlElement
 *
 * @property {number} data-vl-total-items - Attribuut wordt gebruikt om totaal van elementen te bepalen.
 * @property {number} data-vl-current-page - Attribuut wordt gebruikt om huidige pagina te bepalen.
 * @property {number} data-vl-items-per-page - Attribuut wordt gebruikt om het aantal rijen per pagina te bepalen.
 * @property {number} data-vl-pagination-disabled - Attribuut wordt gebruikt om geen pagina links te tonen.
 * @property {boolean} data-vl-align-center - Attribuut wordt gebruikt om de paginatie te centreren.
 * @property {boolean} data-vl-align-right - Attribuut wordt gebruikt om de paginatie rechts uit te lijnen.
 *
 * @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-pager/releases/latest|Release notes}
 * @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-pager/issues|Issues}
 * @see {@link https://webcomponenten.omgeving.vlaanderen.be/demo/vl-pager.html|Demo}
 *
 */
export class VlPager extends vlElement(HTMLElement) {
  static get _observedAttributes() {
    return ['total-items', 'items-per-page', 'current-page', 'pagination-disabled'];
  }

  static get _observedChildClassAttributes() {
    return ['align-center', 'align-right'];
  }

  constructor() {
    super();
    this.shadow(`
      <style>
        @import '/src/style.css';
      </style>
      <div class="vl-pager">
        <ul id="pager-list" class="vl-pager__list">
          <li id="bounds" class="vl-pager__element"></li>
          <li id="page-back-list-item" class="vl-pager__element">
            <a id="page-back-link" class="vl-pager__element__cta vl-link vl-link--bold" href="#" tabindex="0">
              <i class="vl-link__icon vl-link__icon--before vl-vi vl-vi-arrow-left-fat" aria-hidden="true"></i>
              Vorige <span id="previous-items-per-page" class="vl-u-visually-hidden"></span>
            </a>
          </li>
          <li id="page-forward-list-item" class="vl-pager__element">
            <a id="page-forward-link" class="vl-pager__element__cta vl-link vl-link--bold" href="#" tabindex="0">
              Volgende <span id="next-items-per-page" class="vl-u-visually-hidden"></span>
              <i class="vl-link__icon vl-link__icon--after vl-vi vl-vi-arrow-right-fat" aria-hidden="true"></i>
            </a>
          </li>
        </ul>
      </div>
    `);

    this.__addPageBackLinkListener();
    this.__addPageForwardLinkListener();
  }

  get _classPrefix() {
    return 'vl-pager--';
  }

  /**
   * Geeft het aantal pagina's terug.
   *
   * @return {Number} Aantal pagina's.
   */
  get totalPages() {
    return Math.ceil(this.totalItems / this.itemsPerPage);
  }

  /**
   * Geeft het totaal aantal items terug.
   *
   * @return {Number} Totaal aantal items.
   */
  get totalItems() {
    return parseInt(this.getAttribute('total-items'));
  }

  /**
   * Geeft het huidige pagina nummer terug.
   *
   * @return {Number} Huidig pagina nummer.
   */
  get currentPage() {
    const currentPage = parseInt(this.getAttribute('current-page'));
    if (currentPage < 1) {
      return 1;
    } else {
      return currentPage <= this.totalPages ? currentPage : this.totalPages;
    }
  }

  /**
   * Geeft het aantal items per pagina terug.
   *
   * @return {Number} Aantal items per pagina.
   */
  get itemsPerPage() {
    return parseInt(this.getAttribute('items-per-page'));
  }

  get _firstItemNumberOfPage() {
    if (!this.totalItems) {
      return 0;
    } else {
      return (this.currentPage - 1) * this.itemsPerPage + 1;
    }
  }

  get _lastItemNumberOfPage() {
    const lastItemNumber = this._firstItemNumberOfPage + this.itemsPerPage - 1;
    return lastItemNumber > this.totalItems ? this.totalItems : lastItemNumber;
  }

  get _isPagination() {
    return this.getAttribute('pagination-disabled') == undefined;
  }

  get _boundsElement() {
    return this._shadow.querySelector('#bounds');
  }

  get _pagesListElement() {
    return this._shadow.querySelector('.vl-pager__list');
  }

  get _pageElements() {
    return [...this._pagesListElement.querySelectorAll('[data-vl-pager-page]')];
  }

  get _pageSkippedElements() {
    return [...this._pagesListElement.querySelectorAll('[data-vl-pager-page-skipped]')];
  }

  get _pageBackLink() {
    return this._shadow.querySelector('#page-back-link');
  }

  get _pageForwardLink() {
    return this._shadow.querySelector('#page-forward-link');
  }

  get _pageBackListItem() {
    return this._shadow.querySelector('#page-back-list-item');
  }

  get _pageForwardListItem() {
    return this._shadow.querySelector('#page-forward-list-item');
  }

  get _totalItemsElement() {
    return this._shadow.querySelector('#totalItems');
  }

  get _itemsPerPageElementen() {
    const previous = this._shadow.querySelector('#previous-items-per-page');
    const next = this._shadow.querySelector('#next-items-per-page');
    return [previous, next];
  }

  _getBoundsTemplate() {
    return `
      <span class="vl-u-visually-hidden">Rij</span>
      <strong>${this._firstItemNumberOfPage}-${this._lastItemNumberOfPage}</strong> van ${this.totalItems}
    `;
  }

  _getPageTemplate(number) {
    if (this._isPagination) {
      if (number === this.currentPage) {
        return this.__getActivePageTemplate(number);
      } else if (number === 'skipped') {
        return this.__getSkippedPageTemplate();
      } else {
        return this.__getPageTemplate(number);
      }
    } else {
      return ``;
    }
  }

  __getActivePageTemplate(number) {
    return this._template(`
      <li data-vl-pager-page=${number} class="vl-pager__element"> 
        <label>${number}</label>
      </li>
    `);
  }

  __getSkippedPageTemplate() {
    return this._template(`
      <li data-vl-pager-page-skipped class="vl-pager__element">
        <div class="vl-pager__element__cta">...</div>
      </li>
    `);
  }

  __getPageTemplate(number) {
    const template = this._template(`
      <li data-vl-pager-page=${number} class="vl-pager__element"> 
        <a href="#" class="vl-pager__element__cta vl-link vl-link--bold">${number}</a>
      </li>
    `);
    template.firstElementChild.addEventListener('click', (e) => {
      e.preventDefault();
      this.setAttribute('data-vl-current-page', number);
    });
    return template;
  }

  _getItemsPerPageContentTemplate() {
    return `${this.itemsPerPage} rijen`;
  }

  _itemsPerPageChangedCallback(oldValue, newValue) {
    this._update();
  };

  _totalItemsChangedCallback(oldValue, newValue) {
    if (this.totalItems === 0) {
      this._hide(this._element);
    } else {
      this._show(this._element);
      this._update();
    }
  }

  _currentPageChangedCallback(oldValue, newValue) {
    this._update();
    if (oldValue && newValue != oldValue) {
      const event = {detail: {currentPage: Number(newValue), totalPage: this.totalPages, itemsPerPage: this.itemsPerPage, totalItems: this.totalItems}, bubbles: true};
      this.dispatchEvent(new CustomEvent('change', event));
    }
  }

  _paginationDisabledChangedCallback(oldValue, newValue) {
    if (newValue !== undefined) {
      this.__removePageElements();
    }
  }

  _hide(element) {
    element.hidden = true;
  }

  _show(element) {
    element.hidden = false;
  }

  _update() {
    this._updateInfoElement();
    this._updatePagination();
    this._updateListItems();
  }

  _updateInfoElement() {
    this._boundsElement.innerHTML = this._getBoundsTemplate();
    this._itemsPerPageElementen.forEach((span) => {
      span.innerHTML = this._getItemsPerPageContentTemplate();
    });
  }

  _updatePagination() {
    if (this._isPagination) {
      this.__removePageElements();
      if (this.totalPages > 1) {
        const pages = this.__generatePagination(this.currentPage, this.totalPages);
        const templates = pages.map((number) => this._getPageTemplate(number));
        templates.forEach((template) => this._pagesListElement.insertBefore(template, this._pageForwardListItem));
      }
    }
  }

  _updateListItems() {
    this.currentPage <= 1 ? this._hide(this._pageBackListItem) : this._show(this._pageBackListItem);
    this.currentPage >= this.totalPages ? this._hide(this._pageForwardListItem) : this._show(this._pageForwardListItem);
  }

  __generatePagination(currentPage, pageCount) {
    const delta = 2;
    const range = [];
    for (let i = Math.max(2, currentPage - delta); i <= Math.min(pageCount - 1, currentPage + delta); i++) {
      range.push(i);
    }
    if (currentPage - delta > 2) {
      range.unshift('skipped');
    }
    if (currentPage + delta < pageCount - 1) {
      range.push('skipped');
    }
    range.unshift(1);
    range.push(pageCount);
    return range;
  }

  __addPageBackLinkListener() {
    this._pageBackLink.addEventListener('click', (e) => {
      e.preventDefault();
      if (!(this.currentPage - 1 <= 0)) {
        this.setAttribute('data-vl-current-page', this.currentPage - 1);
      }
    });
  }

  __addPageForwardLinkListener() {
    this._pageForwardLink.addEventListener('click', (e) => {
      e.preventDefault();
      if (!(this.currentPage + 1 > this.totalPages)) {
        this.setAttribute('data-vl-current-page', this.currentPage + 1);
      }
    });
  }

  __removePageElements() {
    this._pageElements.forEach((page) => page.remove());
    this._pageSkippedElements.forEach((element) => element.remove());
  }
}

define('vl-pager', VlPager);