import React, { useEffect, useRef } from 'react';
import { useToolbar } from '@ohif/core';
import { ToolboxUI } from './';
import { useToolbox } from '../../contextProviders';

/**
 * A toolbox is a collection of buttons and commands that they invoke, used to provide
 * custom control panels to users. This component is a generic UI component that
 * interacts with services and commands in a generic fashion. While it might
 * seem unconventional to import it from the UI and integrate it into the JSX,
 * it belongs in the UI components as there isn't anything in this component that
 * couldn't be used for a completely different type of app. It plays a crucial
 * role in enhancing the app with a toolbox by providing a way to integrate
 * and display various tools and their corresponding options
 */
function Toolbox({ servicesManager, buttonSectionId, commandsManager, title, ...props }) {
  const { state: toolboxState, api } = useToolbox(buttonSectionId);
  const { onInteraction, toolbarButtons } = useToolbar({
    servicesManager,
    buttonSection: buttonSectionId,
  });

  const prevButtonIdsRef = useRef();

  useEffect(() => {
    const currentButtonIdsStr = JSON.stringify(
      toolbarButtons.map(button => {
        const { id, componentProps } = button;
        if (componentProps.items?.length) {
          return componentProps.items.map(item => `${item.id}-${item.disabled}`);
        }
        return `${id}-${componentProps.disabled}`;
      })
    );

    if (prevButtonIdsRef.current === currentButtonIdsStr) {
      return;
    }

    prevButtonIdsRef.current = currentButtonIdsStr;

    const initializeOptionsWithEnhancements = toolbarButtons.reduce(
      (accumulator, toolbarButton) => {
        const { id: buttonId, componentProps } = toolbarButton;

        const createEnhancedOptions = (options, parentId) => {
          const optionsToUse = Array.isArray(options) ? options : [options];

          return optionsToUse.map(option => {
            if (typeof option.optionComponent === 'function') {
              return option;
            }

            return {
              ...option,
              value:
                toolboxState.toolOptions?.[parentId]?.find(prop => prop.id === option.id)?.value ??
                option.value,
              commands: value => {
                api.handleToolOptionChange(parentId, option.id, value);

                const { isArray } = Array;
                const cmds = isArray(option.commands) ? option.commands : [option.commands];

                cmds.forEach(command => {
                  const isString = typeof command === 'string';
                  const isObject = typeof command === 'object';

                  if (isString) {
                    commandsManager.run(command, { value });
                  } else if (isObject) {
                    commandsManager.run({
                      ...command,
                      commandOptions: { ...command.commandOptions, ...option, value },
                    });
                  }
                });
              },
            };
          });
        };

        const { items, options } = componentProps;

        if (items?.length) {
          items.forEach(({ options, id }) => {
            accumulator[id] = createEnhancedOptions(options, id);
          });
        } else if (options?.length) {
          accumulator[buttonId] = createEnhancedOptions(options, buttonId);
        } else if (options?.optionComponent) {
          accumulator[buttonId] = options.optionComponent;
        }

        return accumulator;
      },
      {}
    );

    api.initializeToolOptions(initializeOptionsWithEnhancements);
  }, [toolbarButtons, api]);

  const handleToolOptionChange = (toolName, optionName, newValue) => {
    api.handleToolOptionChange(toolName, optionName, newValue);
  };

  return (
    <ToolboxUI
      {...props}
      title={title}
      toolbarButtons={toolbarButtons}
      activeToolOptions={toolboxState.toolOptions?.[toolboxState.activeTool]}
      handleToolSelect={id => api.handleToolSelect(id)}
      handleToolOptionChange={handleToolOptionChange}
      onInteraction={onInteraction}
    />
  );
}

export default Toolbox;
