/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
import { ListMixin } from '@vaadin/a11y-base/src/list-mixin.js';

/**
 * A mixin for `nav` elements, facilitating multiple selection of childNodes.
 *
 * @polymerMixin
 * @mixes ListMixin
 */
export const MultiSelectListMixin = (superClass) =>
  class VaadinMultiSelectListMixin extends ListMixin(superClass) {
    static get properties() {
      return {
        /**
         * Specifies that multiple options can be selected at once.
         */
        multiple: {
          type: Boolean,
          value: false,
          reflectToAttribute: true,
          observer: '_multipleChanged',
        },

        /**
         * Array of indexes of the items selected in the items array
         * Note: Not updated when used in single selection mode.
         * @type {number[] | null | undefined}
         */
        selectedValues: {
          type: Array,
          notify: true,
          value: () => [],
        },
      };
    }

    static get observers() {
      return ['_enhanceMultipleItems(items, multiple, selected, disabled, selectedValues)'];
    }

    /** @protected */
    ready() {
      // Should be attached before click listener in list-mixin
      this.addEventListener('click', (e) => this._onMultipleClick(e));

      super.ready();
    }

    /** @private */
    _enhanceMultipleItems(items, multiple, _selected, _disabled, selectedValues) {
      if (!items || !multiple) {
        return;
      }

      if (selectedValues) {
        const selectedItems = selectedValues.map((selectedId) => items[selectedId]);
        items.forEach((item) => {
          item.selected = selectedItems.includes(item);
        });
      }

      this._scrollToLastSelectedItem();
    }

    /** @private */
    _scrollToLastSelectedItem() {
      const lastSelectedItem = this.selectedValues.slice(-1)[0];
      if (lastSelectedItem && !lastSelectedItem.disabled) {
        this._scrollToItem(lastSelectedItem);
      }
    }

    /**
     * @param {!MouseEvent} event
     * @protected
     */
    _onMultipleClick(event) {
      const item = this._filterItems(event.composedPath())[0];
      const idx = item && !item.disabled ? this.items.indexOf(item) : -1;
      if (idx < 0 || !this.multiple) {
        return;
      }

      event.preventDefault();
      if (this.selectedValues.includes(idx)) {
        this.selectedValues = this.selectedValues.filter((v) => v !== idx);
      } else {
        this.selectedValues = this.selectedValues.concat(idx);
      }
    }

    /** @private */
    _multipleChanged(value, oldValue) {
      // Changing from multiple to single selection, clear selection.
      if (!value && oldValue) {
        this.selectedValues = [];
        this.items.forEach((item) => {
          item.selected = false;
        });

        this.removeAttribute('aria-multiselectable');
      }

      // Changing from single to multiple selection, add selected to selectedValues.
      if (value && !oldValue) {
        this.setAttribute('aria-multiselectable', 'true');

        if (this.selected !== undefined) {
          this.selectedValues = [...this.selectedValues, this.selected];
          this.selected = undefined;
        }
      }
    }

    /**
     * Fired when the selection is changed.
     * Not fired in single selection mode.
     *
     * @event selected-values-changed
     * @param {Object} detail
     * @param {Object} detail.value the array of indexes of the items selected in the items array.
     */
  };
