import { Utility } from '../../core/utility';
import { EventManager, EventWrapper, EVENT_TYPE } from '../../lib/event-manager/event-manager';

const MASS_INPUT_SELECTOR = '.massinput';
const RECIPIENT_CATEGORIES_SELECTOR = '.recipient-categories';
const RECIPIENT_CATEGORY_SELECTOR = '.recipient-category';
const RECIPIENT_CATEGORY_CHECKBOX_SELECTOR = '.recipient-category__checkbox';
const RECIPIENT_CATEGORY_OPTIONS_SELECTOR = '.recipient-category__options';
const RECIPIENT_CATEGORY_TOGGLE_ALL_SELECTOR = '.recipient-category__toggle-all [type="checkbox"]';
const RECIPIENT_CATEGORY_CHECKED_COUNTER_SELECTOR = '.recipient-category__checked-counter';


@Utility({
  selector: RECIPIENT_CATEGORIES_SELECTOR,
})
export class CommunicationRecipients {
  massInputElement;
  _element;

  _eventManager;

  constructor(element) {
    if (!element) {
      throw new Error('Communication Recipient utility cannot be setup without an element!');
    }
    this._element = element;
    this._eventManager = new EventManager();
    this.massInputElement = this._element.closest(MASS_INPUT_SELECTOR);

    this.setupRecipientCategories();

    this._eventManager.registerNewMutationObserver(this.setupRecipientCategories.bind(this), this.massInputElement, { childList: true });
  }

  setupRecipientCategories() {
    Array.from(this.massInputElement.querySelectorAll(RECIPIENT_CATEGORY_SELECTOR)).forEach(this.setupRecipientCategory.bind(this));
  }

  _removeCheckedCounter() {
  let checkedCounters = this._element.querySelectorAll(RECIPIENT_CATEGORY_CHECKED_COUNTER_SELECTOR);
  checkedCounters.forEach((checkedCounter) => {
    checkedCounter.innerHTML = '';
  });
  }

  destroy() {
    this._eventManager.cleanUp();
    this._removeCheckedCounter();
  }


  setupRecipientCategory(recipientCategoryElement) {
    const categoryCheckbox = recipientCategoryElement.querySelector(RECIPIENT_CATEGORY_CHECKBOX_SELECTOR);
    const categoryOptions = recipientCategoryElement.querySelector(RECIPIENT_CATEGORY_OPTIONS_SELECTOR);
  
    if (categoryOptions) {
      const categoryCheckboxes = Array.from(categoryOptions.querySelectorAll('[type="checkbox"]'));
      const toggleAllCheckbox = recipientCategoryElement.querySelector(RECIPIENT_CATEGORY_TOGGLE_ALL_SELECTOR);
  
      // setup category checkbox to toggle all child checkboxes if changed
      const categoryToggleEvent = new EventWrapper(EVENT_TYPE.CHANGE,(() => {
        categoryCheckboxes.filter(checkbox => !checkbox.disabled).forEach(checkbox => {
          checkbox.checked = categoryCheckbox.checked;
        });
        updateCheckedCounter(recipientCategoryElement, categoryCheckboxes);
        updateToggleAllCheckbox(toggleAllCheckbox, categoryCheckboxes);
      }).bind(this), categoryCheckbox );
      this._eventManager.registerNewListener(categoryToggleEvent);

      // update counter and toggle checkbox initially
      updateCheckedCounter(recipientCategoryElement, categoryCheckboxes);
      updateToggleAllCheckbox(toggleAllCheckbox, categoryCheckboxes);
  
      // register change listener for individual checkboxes
      categoryCheckboxes.forEach(checkbox => {
        const individualToggleEvent = new EventWrapper(EVENT_TYPE.CHANGE, (() => {
          updateCheckedCounter(recipientCategoryElement, categoryCheckboxes);
          updateToggleAllCheckbox(toggleAllCheckbox, categoryCheckboxes);
        }).bind(this), checkbox);
        this._eventManager.registerNewListener(individualToggleEvent);
      });
  
      // register change listener for toggle all checkbox
      if (toggleAllCheckbox) {
        const toggleAllEvent = new EventWrapper(EVENT_TYPE.CHANGE, (() => {
          categoryCheckboxes.filter(checkbox => !checkbox.disabled).forEach(checkbox => {
            checkbox.checked = toggleAllCheckbox.checked;
          });
          updateCheckedCounter(recipientCategoryElement, categoryCheckboxes);
        }).bind(this), toggleAllCheckbox);
        this._eventManager.registerNewListener(toggleAllEvent);
      }
    }
  }
}

// update checked state of toggle all checkbox based on all other checkboxes
function updateToggleAllCheckbox(toggleAllCheckbox, categoryCheckboxes) {
  const allChecked = categoryCheckboxes.reduce((acc, checkbox) => acc && checkbox.checked, true);
  toggleAllCheckbox.checked = allChecked;
}

// update value of checked counter
function updateCheckedCounter(recipientCategoryElement, categoryCheckboxes) {
  const checkedCounter = recipientCategoryElement.querySelector(RECIPIENT_CATEGORY_CHECKED_COUNTER_SELECTOR);
  const checkedCheckboxes = categoryCheckboxes.reduce((acc, checkbox) => checkbox.checked ? acc + 1 : acc, 0);
  checkedCounter.innerHTML = checkedCheckboxes + '/' + categoryCheckboxes.length;
}
