/**
 * Applies attributes based on the user's current Vizality settings.
 * @module Settings
 * @memberof Builtin.Attributes.Vizality
 */

import { DefaultSettings, ActionTypes } from '@vizality/constants';
import { toKebabCase } from '@vizality/util/string';
import { FluxDispatcher } from '@vizality/webpack';

export const labels = [ 'Vizality', 'Settings' ];

export default () => {
  const root = document.documentElement;

  /**
   * 
   * @param {string} setting 
   * @param {any} value 
   */
  const setAttribute = (setting, value) => {
    const { get } = vizality.settings;

    /*
     * These are the settings we want to track and add as attributes.
     */
    const attributes = {};
    for (const setting of Object.entries(DefaultSettings)) {
      attributes[setting[0]] = get(setting[0], setting[1]);
    }

    /**
     * Check if the setting is defined by default.
     * If it is, overwrite it with the new value.
     */
    if (attributes.hasOwnProperty(setting)) {
      attributes[setting] = value;
    }

    const activeSettings = Object.keys(attributes).filter(a => attributes[a]);

    /**
     * Check if there are any active settings, if not remove the attribute.
     */
    if (!activeSettings.length) {
      root.removeAttribute('vz-settings');
    /**
     * Otherwise set them as vz-settings attribute values.
     */
    } else {
      root.setAttribute('vz-settings', activeSettings.map(setting => toKebabCase(setting)).join(', '));
    }
  };

  /**
   * Set the attributes initially.
   */
  setAttribute();

  /**
   * Handles settings toggles.
   * @param {object} payload Payload
   * @param {string} payload.category Settings category
   * @param {string} payload.setting Setting key
   */
  // eslint-disable-next-line no-unused-vars
  const handleToggle = ({ category, setting }) => {
    /*
     * @note We have to send the opposite of what the value reads here
     * because of async issues, it seems. It retrieves the previous value instead
     * of the current, so taking the inverse gives us the current value.
     */
    const value = !vizality.settings.get(setting);
    setAttribute(setting, value);
  };

  /**
   * Handles settings updates.
   * @param {object} payload Payload
   * @param {string} payload.category Settings category
   * @param {string} payload.setting Setting key
   * @param {...any} payload.value Setting value
   */
  // eslint-disable-next-line no-unused-vars
  const handleUpdate = ({ category, setting, value }) => {
    setAttribute(setting, value);
  };


  /**
   * Subscribe to Vizality settings flux updates.
   */
  FluxDispatcher?.subscribe(ActionTypes.VIZALITY_TOGGLE_SETTING, handleToggle);
  FluxDispatcher?.subscribe(ActionTypes.VIZALITY_UPDATE_SETTING, handleUpdate);

  /**
   * Unsubscribe from flux and remove attributes.
   */
  return () => {
    FluxDispatcher?.unsubscribe(ActionTypes.VIZALITY_TOGGLE_SETTING, handleToggle);
    FluxDispatcher?.unsubscribe(ActionTypes.VIZALITY_UPDATE_SETTING, handleUpdate);
    root.removeAttribute('vz-settings');
  };
};
