import React, { useEffect, useMemo, useState } from 'react';
import type { ComponentType } from 'react';
import Icon from '../Icon';
import { EditorEvents, ToolbarEvents } from './constants';
import {
  StyledSeparator,
  StyledToolbar,
  StyledToolbarButton,
} from './StyledToolbar';
import type { ToolbarButtonName } from './types';
import type { IconProps } from '../Icon';
import useRichTextEditorEvents from './hooks/useRichTextEditorEvents';

type ToolbarButtonProps = {
  icon: IconProps['icon'];
  onPress: () => void;
  testID?: string;
  selected: boolean;
};
const ToolbarButton: ComponentType<ToolbarButtonProps> = ({
  icon,
  onPress,
  testID,
  selected,
}: ToolbarButtonProps) => (
  <StyledToolbarButton selected={selected} onPress={onPress} testID={testID}>
    <Icon size="small" icon={icon} />
  </StyledToolbarButton>
);

interface ButtonConfig {
  icon: IconProps['icon'];
  eventName: ToolbarEvents;
  standalone?: boolean;
}

const buttonConfigs: Partial<Record<ToolbarButtonName, ButtonConfig>> = {
  bold: {
    icon: 'format-bold',
    eventName: ToolbarEvents.Bold,
  },
  italic: {
    icon: 'format-italic',
    eventName: ToolbarEvents.Italic,
  },
  underline: {
    icon: 'format-underlined',
    eventName: ToolbarEvents.Underline,
  },
  bulletedList: {
    icon: 'format-list-bulleted',
    eventName: ToolbarEvents.BulletedList,
    standalone: true,
  },
  numberedList: {
    icon: 'format-list-numbered',
    eventName: ToolbarEvents.NumberedList,
    standalone: true,
  },
  headingOne: {
    icon: 'format-heading1',
    eventName: ToolbarEvents.HeadingOne,
    standalone: true,
  },
  headingTwo: {
    icon: 'format-heading2',
    eventName: ToolbarEvents.HeadingTwo,
    standalone: true,
  },
};

const defaultButtons: ToolbarButtonName[] = [
  'bold',
  'italic',
  'underline',
  '|',
  'bulletedList',
  'numberedList',
  '|',
  'headingOne',
  'headingTwo',
];

export interface EditorToolbarProps {
  /**
   * List of buttons to display in toolbar
   */
  buttons?: ToolbarButtonName[];
  /**
   * Unique name used to communicate with webview, should be the same with the RichTextEditor component it used with
   */
  name: string;
  /**
   * Testing ID of the component
   */
  testID?: string;
}

const EditorToolbar = ({
  name,
  buttons = defaultButtons,
  testID,
}: EditorToolbarProps) => {
  const [show, setShow] = useState(false);

  const { emitEvent, subscribeToEvents } = useRichTextEditorEvents(name);
  const [toolbarButtonState, setToolbarButtonState] = useState<
    Record<string, boolean>
  >({});

  useEffect(() => {
    const removeFocusListener = subscribeToEvents(
      EditorEvents.EditorFocus,
      () => setShow(true)
    );
    const removeBlurListener = subscribeToEvents(EditorEvents.EditorBlur, () =>
      setShow(false)
    );
    const removeEditorChangeListener = subscribeToEvents(
      EditorEvents.EditorChange,
      ({ toolbarState = {} }) => {
        setToolbarButtonState(toolbarState);
      }
    );

    return () => {
      removeFocusListener();
      removeBlurListener();
      removeEditorChangeListener();
    };
  }, []);

  const toolbarButtons = useMemo(
    () =>
      buttons.map((button, index) => {
        if (button === '|') {
          return <StyledSeparator key={index} />;
        }
        const config = buttonConfigs[button];
        if (config) {
          return (
            <ToolbarButton
              key={button}
              testID={config.icon}
              icon={config.icon}
              onPress={() => {
                emitEvent({
                  type: config.eventName,
                  data: null,
                });
              }}
              selected={toolbarButtonState[config.eventName]}
            />
          );
        }
        return null;
      }),
    [toolbarButtonState, buttons]
  );

  if (show) {
    return <StyledToolbar testID={testID}>{toolbarButtons}</StyledToolbar>;
  }
  return null;
};

export default EditorToolbar;
