<template>
  <div class="mc-pagination" :class="{ 'mc-pagination--light': light }">
    <component
      :is="hrefPrev ? 'a' : 'button'"
      :type="hrefPrev ? null : 'button'"
      :href="hrefPrev"
      class="mc-button mc-button--solid-neutral mc-button--square mc-button--s@from-l"
      aria-label="Previous Page"
      :disabled="value <= 1 || disabled"
      @click="previousPage(currentPage - 1)"
    >
      <MIcon name="ArrowArrowLeft24" class="mc-button__icon" />
    </component>

    <div v-if="!light" class="mc-pagination__field">
      <MSelect
        :id="`selectpagination${selectId}`"
        :model-value="currentPage"
        :options="formattedOptions"
        :disabled="disabled"
        :aria-label="selectAriaLabel"
        class="mc-pagination__select"
        @update:model-value="changePage(Number($event))"
      >
        <template #text="{ option }">
          <!-- @slot Use this slot if you wish to customise the display of text for `<option>` elements of the MSelect -->
          <slot name="text" :option="{ ...option, length }">
            {{ option.text }}
          </slot>
        </template>
      </MSelect>
    </div>

    <component
      :is="hrefNext ? 'a' : 'button'"
      :type="hrefNext ? null : 'button'"
      :href="hrefNext"
      class="mc-button mc-button--solid-neutral mc-button--square mc-button--s@from-l"
      aria-label="Next Page"
      :disabled="value >= length || disabled"
      @click="nextPage(currentPage + 1)"
    >
      <MIcon name="ArrowArrowRight24" class="mc-button__icon" />
    </component>
  </div>
</template>

<script>
import { useId } from 'vue';
import MIcon from '../icon/MIcon.vue';
import MSelect from '../select/MSelect.vue';

/**
 * > Pagination enables users to navigate from a page to another one, especially when a large content needs to be splitted in several parts. It's mainly used on pages like the search engine result page or the list pages.
 *
 * The `MPagination` component is the **Vue.js** implementation of the **Pagination** component of Mozaic Design System.<br/>
 * The full specification of this component is available in [the associated documentation](https://mozaic.adeo.cloud/components/pagination/).
 */
export default {
  name: 'MPagination',
  components: {
    MIcon,
    MSelect,
  },
  props: {
    /**
     * The number of pages
     */
    length: {
      type: Number,
      default: 0,
    },
    /**
     * The value of the current or selected page. _(Can be used with `v-model`)_
     */
    value: {
      type: Number,
      default: 0,
    },
    /**
     * Text inserted in `<option>` elements to separate the current page from the total number of pages
     */
    // TODO: See how to rename this variable with a more meaningful name
    pageLabel: {
      type: String,
      default: 'sur',
    },
    /**
     * Activates the "light" variation of the component. This variation contains only the buttons and hides the MSelect element.
     */
    light: {
      type: Boolean,
      default: false,
    },
    /**
     * If set, changes the previous `<button>` tag to an `<a>` tag
     */
    hrefPrev: {
      type: String,
      default: null,
    },
    /**
     * If set, changes the next `<button>` tag to an `<a>` tag
     */
    hrefNext: {
      type: String,
      default: null,
    },
    /**
     * Allows to disabled the component
     */
    disabled: {
      type: Boolean,
      default: false,
    },
    /**
     * Reduces pagination to essential pages (min 10p)
     */
    showPartial: {
      type: Boolean,
      default: false,
    },
    /**
     * Text value of the `aria-label` attribute of the select element
     */
    selectAriaLabel: {
      type: String,
      default: 'Select page',
    },
  },
  emits: ['update:value', 'on-update-page', 'on-previous-page', 'on-next-page'],
  setup: function () {
    return {
      selectId: useId(),
    };
  },
  data: function () {
    return {
      currentPage: Number(this.value),
    };
  },
  computed: {
    formattedOptions() {
      const pageOptions = [];
      if (this.showPartial && this.length > 10) {
        // Set 3 first 3 last page by default
        for (
          let i = 1, j = this.length;
          i <= 3, j >= this.length - 2;
          i++, j--
        ) {
          this.formatData(pageOptions, i);
          this.formatData(pageOptions, j);
        }
        if (
          !pageOptions.some((page) => page.index === this.currentPage - 1) &&
          this.currentPage - 1 != 0
        ) {
          this.formatData(pageOptions, this.currentPage - 1);
        }
        if (!pageOptions.some((page) => page.index === this.currentPage)) {
          this.formatData(pageOptions, this.currentPage);
        }
        if (
          !pageOptions.some((page) => page.index === this.currentPage + 1) &&
          this.currentPage != this.length
        ) {
          this.formatData(pageOptions, this.currentPage + 1);
        }
        // Reorder pagination
        pageOptions.sort((a, b) => a.index - b.index);
      } else {
        // all pages
        for (let i = 1; i <= this.length; i++) {
          this.formatData(pageOptions, i);
        }
      }
      return pageOptions;
    },
  },
  watch: {
    value: {
      handler(newPage) {
        this.currentPage = newPage;
      },
    },
  },
  methods: {
    formatData(pageOptions, index) {
      pageOptions.push({
        text: `${index} ${this.pageLabel} ${this.length}`,
        value: index,
        index: index,
      });
    },
    hasPreviousPageListener() {
      return this.$attrs && this.$attrs['on-previous-page'];
    },
    hasNextPageListener() {
      return this.$attrs && this.$attrs['on-next-page'];
    },

    changePage(newPage) {
      // TODO: See how to standardize these two events
      /**
       * Triggered when the current page value is updated.
       * - @arg {number} [newPage] - the updated current page value
       */
      this.$emit('on-update-page', newPage);
      /**
       * Triggered when the current page value is updated
       */
      this.$emit('update:value', newPage);
    },

    previousPage(newPage) {
      if (this.hasPreviousPageListener()) {
        /**
         * Triggered by clicking on the "prev" button
         * - @arg {number} [newPage] - the updated current page value
         */
        this.$emit('on-previous-page', newPage);
      } else {
        this.changePage(newPage);
      }
    },
    nextPage(newPage) {
      if (this.hasNextPageListener()) {
        /**
         * Triggered by clicking on the "next" button
         * - @arg {number} [newPage] - the updated current page value
         */
        this.$emit('on-next-page', newPage);
      } else {
        this.changePage(newPage);
      }
    },
  },
};
</script>

<style lang="scss" scoped>
@import 'settings-tools/all-settings';
@import 'components/c.button';
@import 'components/c.pagination';
</style>
