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

/**
 * Gebruik de radio group mixin om logica toe te voegen aan een group van radio elementen.
 * @mixin vlRadioGroup
 */
export const vlRadioGroup = {
  /**
   * Zet het key events registered attribuut.
   */
  setKeyEventsRegistered() {
    const parent = this._parentElement();
    parent.setAttribute('data-vl-key-events-registered', '');
  },

  /**
   * Geeft terug of de key events reeds geregistreerd zijn.
   * @return {boolean}
   */
  hasKeyEventsRegistered() {
    const parent = this._parentElement();
    return parent.hasAttribute('data-vl-key-events-registered');
  },

  /**
   * Zet het focus transmit attribuut.
   */
  setFocusTransmitted() {
    const parent = this._parentElement();
    parent.setAttribute('data-vl-focus-transmitted', '');
  },

  /**
   * Geeft terug of de focus transmit reeds gebeurd is.
   * @return {boolean}
   */
  hasFocusTransmitted() {
    const parent = this._parentElement();
    return parent.hasAttribute('data-vl-focus-transmitted');
  },

  /**
   * Activeer keydown event listener om het navigeren over radio group elementen toe te laten.
   * @param {Object[]} radios - Een Array van radio HTMLElement
   */
  registerKeyEvents(radios) {
    if (!this.hasKeyEventsRegistered()) {
      const keys = {
        left: 37,
        up: 38,
        right: 39,
        down: 40,
      };
      const parent = this._parentElement();
      parent.addEventListener('keydown', (event) => {
        const enabledRadios = radios.filter((radio) => !radio.disabled);
        const includesArrowKey = Object.values(keys).includes(event.keyCode);
        if (includesArrowKey) {
          event.preventDefault();
          const focusedRadio = enabledRadios.find((radio) => radio.hasFocus);
          const firstRadio = enabledRadios[0];
          const lastRadio = enabledRadios[enabledRadios.length - 1];
          switch (event.keyCode) {
            case keys.up:
            case keys.left: {
              const previousRadio = enabledRadios[enabledRadios.indexOf(focusedRadio) - 1];
              (previousRadio || lastRadio).check();
              break;
            }
            case keys.down:
            case keys.right: {
              const nextRadio = enabledRadios[enabledRadios.indexOf(focusedRadio) + 1];
              (nextRadio || firstRadio).check();
              break;
            }
            default:
              break;
          }
        }
      });
    }
    this.setKeyEventsRegistered();
  },

  /**
   * Delegeert de focus correct door naar de radio child elementen.
   *
   * @param {Object[]} radios - Een Array van radio HTMLElement
   */
  transmitFocus(radios) {
    if (!this.hasFocusTransmitted()) {
      const parent = this._parentElement();
      parent.addEventListener('focus', () => {
        parent.addEventListener('keyup', (event) => {
          if (event.shiftKey) {
            const checkedRadio = enabledRadios.find((radio) => radio.checked);
            const latestRadio = enabledRadios[enabledRadios.length - 1];
            (checkedRadio || latestRadio).focus();
          }
        }, {once: true});
        const enabledRadios = radios.filter((radio) => !radio.disabled);
        const checkedRadio = enabledRadios.find((radio) => radio.checked);
        const firstRadio = enabledRadios[0];
        if (checkedRadio || firstRadio) {
          (checkedRadio || firstRadio).focus();
        }
      });
    }
    this.setFocusTransmitted();
  },

  _parentElement() {
    return this.parentElement || this.getRootNode().host || this.getRootNode();
  },
};

/**
 * VlRadioGroup
 * @class
 * @classdesc De radio group bundelt verschillende radio elementen die samenhoren.
 *
 * @extends HTMLElement
 * @mixes vlElement
 *
 * @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-radio/releases/latest|Release notes}
 * @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-radio/issues|Issues}
 * @see {@link https://webcomponenten.omgeving.vlaanderen.be/demo/vl-radio-group.html|Demo}
 */
export class VlRadioGroup extends vlElement(HTMLElement) {
  constructor() {
    super(`<slot></slot>`);
    Object.assign(this, vlRadioGroup);
  }

  connectedCallback() {
    this._groupRadios();
    this._processTabIndex();
    this._transmitFocus();
  }

  /**
   * Geeft de radio elementen terug.
   * @return {Array.<HTMLInputElement>}
   */
  get radios() {
    return [...this.querySelectorAll('vl-radio')];
  }

  /**
   * Geeft het radio element die checked is terug.
   * @return {HTMLInputElement}
   */
  get checkedRadio() {
    return this.radios.find((radio) => radio.checked);
  }

  _groupRadios() {
    this.radios.forEach((radio) => radio.setAttribute('data-vl-name', 'radio'));
  }

  _processTabIndex() {
    this.tabIndex = 0;
    this.radios.forEach((radio) => radio.addEventListener('focus', () => this.tabIndex = -1));
    this.radios.forEach((radio) => radio.addEventListener('blur', () => this.tabIndex = 0));
  }

  _groupRadios() {
    this.radios.forEach((radio) => radio.setAttribute('data-vl-name', 'radio'));
  }

  _transmitFocus() {
    this.tabIndex = 0;
    this.addEventListener('focus', () => {
      this.addEventListener('keyup', (event) => {
        if (event.shiftKey) {
          this.radios[this.radios.length - 1].focus();
        }
      }, {once: true});
      this.radios[0].focus();
    });
    this.radios.forEach((radio) => radio.addEventListener('focus', () => this.tabIndex = -1));
    this.radios.forEach((radio) => radio.addEventListener('blur', () => this.tabIndex = 0));
  }
}

define('vl-radio-group', VlRadioGroup);