/***
 * Copyright (c) 2016 - 2022 Alex Grant (@localnerve), LocalNerve LLC
 * Copyrights licensed under the BSD License. See the accompanying LICENSE file
 * for terms.
 *
 * Staticly define all possible code splits.
 * Split definitions have to be static for webpack to generate bundles.
 */
/* global Promise */
import debugLib from 'debug';
import * as actionsInterface from 'application/actions/interface';
import app from 'application/app';

const debug = debugLib('utils:splits');
const __DEV__ = process.env.NODE_ENV !== 'production';

/***
 * Add new static split handlers here.
 * These are referenced from backend data to signal a change in the
 * behavior of code.
 */
export const splitHandlers = {
  settings: injectSplitSettings
};

/**
 * Download the Fluxible component 'Settings' and inject it into the main
 * program. Settings are available only in an on-demand dialog, so it doesn't
 * need to be in the main bundle.
 *
 * download and injection is idempotent, no consequence from re-exec.
 *
 * @param {Object} context - The fluxible action context.
 * @param {Object} payload - The settings payload.
 * @param {Object} payload.action - The settings action definition.
 * @param {String} payload.action.name - The settings action name.
 * @param {String} payload.component - The settings component name.
 * @param {Function} updateAction - The action to execute after load,
 * actions/modal.updateComponent.
 * @returns {Promise} A promise that resolves when the code is downloaded and
 * injected.
 */
function injectSplitSettings (context, payload, updateAction) {
  debug('injectSplitSettings payload', payload);

  return Promise.all([
    import(
      /* webpackChunkName: "settings" */
      'application/stores/SettingsStore'
    ),
    import(
      /* webpackChunkName: "settings" */
      'application/actions/settings'
    ),
    import(
      /* webpackChunkName: "settings" */
      'application/components/pages/settings'
    )
  ]).then(([
    { default: SettingsStore },
    { default: settingsAction },
    { default: settingsComponent }
  ]) => {
      debug(
        'injectSplitSettings imported',
        '\nSettingsStore', SettingsStore,
        '\nsettingsAction', settingsAction,
        '\nsettingsComponent', settingsComponent
      );

      app.registerStore(SettingsStore);
      actionsInterface.putAction(payload.action.name, settingsAction);

      const updatePayload = {
        resource: payload.component,
        component: settingsComponent
      };

      if (__DEV__) {
        updatePayload.emulateError = payload.emulateError;
      }

      return new Promise((resolve, reject) => {
        // Settings is a modal component, so give it to the modal store.
        context.executeAction(updateAction, updatePayload, err => {
          if (err) {
            debug('updateAction failed', err);
            return reject(err);
          }
          resolve();
        });
      });
    });
}
