import * as React from 'react';
import { ElementsSideBar } from '../ElementsList/ElementsSideBar';
import { History } from '../History/History';
import { Bar, BAR_WIDTH } from '../Bar/Bar';
import { Symbols } from '../Symbols/Symbols';
import { SymbolsSidebar } from '../SymbolsList/SymbolsSidebar';
import { type PropertyType } from '../../Enums/PropertyType';
import { Messages } from '../Messages/Messages';
import { Sidebar } from '../Sidebar/Sidebar';
import { Components } from '../Components/Components';
import { Viewer } from '../Viewer/Viewer';
import { Settings } from '../Settings/Settings';
import { type IMessage } from '../../Interfaces/IMessage';
import { DISABLE_API } from '../../utils/default';
import { UseWorker, UseAsync } from './UseWorker';
import { FindContainerById } from '../../utils/itertools';
import { type IEditorState } from '../../Interfaces/IEditorState';
import { GetCurrentHistoryState } from '../Editor/Editor';
import { Text } from '../Text/Text';
import { IReplaceContainer } from '../../Interfaces/IReplaceContainer';
import { Dispatch } from 'react';

export interface IUIProps {
  editorState: IEditorState
  replaceContainer: IReplaceContainer
  selectContainer: (containerId: string) => void
  deleteContainer: (containerId: string) => void
  onPropertyChange: (key: string, value: string | number | boolean | number[], type?: PropertyType) => void
  addOrReplaceContainer: (type: string) => void
  addContainerAt: (index: number, type: string, parent: string) => void
  addSymbol: (type: string) => void
  onSymbolPropertyChange: (key: string, value: string | number | boolean) => void
  selectSymbol: (symbolId: string) => void
  deleteSymbol: (symbolId: string) => void
  saveEditorAsJSON: () => void
  saveEditorAsSVG: () => void
  loadState: (move: number) => void
  setReplaceContainer: Dispatch<React.SetStateAction<IReplaceContainer>>

}

export enum SidebarType {
  None,
  Components,
  ComponentsExpanded,
  Symbols,
  SymbolsExpanded,
  History,
  Messages,
  Settings
}

function UseSetOrToggleSidebar(
  selectedSidebar: SidebarType,
  setSelectedSidebar: React.Dispatch<React.SetStateAction<SidebarType>>
): (newSidebarType: SidebarType) => void {
  return (newSidebarType) => {
    if (newSidebarType === selectedSidebar) {
      setSelectedSidebar(SidebarType.None);
      return;
    }

    setSelectedSidebar(newSidebarType);
  };
}

export function UI({ editorState, replaceContainer, setReplaceContainer, ...methods }: IUIProps): JSX.Element {
  const [selectedSidebar, setSelectedSidebar] = React.useState<SidebarType>(SidebarType.Components);

  const [messages, setMessages] = React.useState<IMessage[]>([]);
  const current = GetCurrentHistoryState(editorState.history, editorState.historyCurrentStep);
  const configuration = editorState.configuration;

  // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
  if (window.Worker && !DISABLE_API) {
    UseWorker(
      current,
      configuration.APIConfiguration?.apiGetFeedbackUrl,
      setMessages
    );
  } else if (!DISABLE_API) {
    UseAsync(
      current,
      configuration.APIConfiguration?.apiGetFeedbackUrl,
      setMessages
    );
  }

  // Please use setOrToggleSidebar rather than setSelectedSidebar, so we can close the sidebar
  const setOrToggleSidebar = UseSetOrToggleSidebar(selectedSidebar, setSelectedSidebar);

  let leftSidebarTitle = '';
  let rightSidebarTitle = '';
  let leftChildren: JSX.Element = (<></>);
  let rightChildren: JSX.Element = (<></>);

  const mainContainer = FindContainerById(current.containers, current.mainContainer);

  if (mainContainer === undefined) {
    throw new Error('Tried to initialized UI but there is no main container!');
  }

  const selectedContainer = FindContainerById(current.containers, current.selectedContainerId);
  const selectedSymbol = current.symbols.get(current.selectedSymbolId);

  switch (selectedSidebar) {
    case SidebarType.Components:
      leftSidebarTitle = Text({ textId: '@Components' });

      leftChildren = <Components
        selectedContainer={selectedContainer}
        componentOptions={configuration.AvailableContainers}
        categories={configuration.Categories}
        buttonOnClick={methods.addOrReplaceContainer}
        replaceContainer={replaceContainer}
        setReplaceContainer={setReplaceContainer}/>;
      rightSidebarTitle = Text({ textId: '@Elements' });
      rightChildren = <ElementsSideBar
        containers={current.containers}
        mainContainer={mainContainer}
        symbols={current.symbols}
        selectedContainer={selectedContainer}
        onPropertyChange={methods.onPropertyChange}
        selectContainer={methods.selectContainer}
        addContainer={methods.addContainerAt}
        isExpanded ={false}
        onExpandChange={() => { setOrToggleSidebar(SidebarType.ComponentsExpanded); } }
      />;
      break;
    case SidebarType.ComponentsExpanded:
      leftSidebarTitle = Text({ textId: '@Components' });
      leftChildren = <Components
        selectedContainer={selectedContainer}
        componentOptions={configuration.AvailableContainers}
        categories={configuration.Categories}
        buttonOnClick={methods.addOrReplaceContainer}
        replaceContainer={replaceContainer}
        setReplaceContainer={setReplaceContainer}/>;
      rightSidebarTitle = Text({ textId: '@Elements' });
      rightChildren = <ElementsSideBar
        containers={current.containers}
        mainContainer={mainContainer}
        symbols={current.symbols}
        selectedContainer={selectedContainer}
        onPropertyChange={methods.onPropertyChange}
        selectContainer={methods.selectContainer}
        addContainer={methods.addContainerAt}
        isExpanded ={true}
        onExpandChange={() => { setOrToggleSidebar(SidebarType.Components); } }
      />;
      break;
    case SidebarType.Symbols:
      leftSidebarTitle = Text({ textId: '@SymbolsLeft' });
      leftChildren = <Symbols
        componentOptions={configuration.AvailableSymbols}
        buttonOnClick={methods.addSymbol}
      />;
      rightSidebarTitle = Text({ textId: '@SymbolsRight' });
      rightChildren = <SymbolsSidebar
        selectedSymbolId={current.selectedSymbolId}
        symbols={current.symbols}
        onPropertyChange={methods.onSymbolPropertyChange}
        selectSymbol={methods.selectSymbol}
        isExpanded ={false}
        onExpandChange={() => { setOrToggleSidebar(SidebarType.SymbolsExpanded); } }
      />;
      break;
    case SidebarType.SymbolsExpanded:
      leftSidebarTitle = Text({ textId: '@SymbolsLeft' });
      leftChildren = <Symbols
        componentOptions={configuration.AvailableSymbols}
        buttonOnClick={methods.addSymbol}
      />;
      rightSidebarTitle = Text({ textId: '@SymbolsRight' });
      rightChildren = <SymbolsSidebar
        selectedSymbolId={current.selectedSymbolId}
        symbols={current.symbols}
        onPropertyChange={methods.onSymbolPropertyChange}
        selectSymbol={methods.selectSymbol}
        isExpanded ={true}
        onExpandChange={() => { setOrToggleSidebar(SidebarType.Symbols); }}
      />;
      break;

    case SidebarType.History:
      leftSidebarTitle = Text({ textId: '@Timeline' });
      leftChildren = <History
        history={editorState.history}
        historyCurrentStep={editorState.historyCurrentStep}
        jumpTo={methods.loadState}
      />;
      break;

    case SidebarType.Messages:
      leftSidebarTitle = Text({ textId: '@Messages' });
      leftChildren = <Messages
        historyState={current}
        messages={messages}
        clearMessage={() => { setMessages([]); }}
      />;
      break;

    case SidebarType.Settings:
      leftSidebarTitle = Text({ textId: '@Settings' });
      leftChildren = <Settings
        saveEditorAsJSON={methods.saveEditorAsJSON}
        saveEditorAsSVG={methods.saveEditorAsSVG}
      />;
      break;
  }

  const isLeftSidebarOpen = selectedSidebar !== SidebarType.None;
  const isRightSidebarOpen = selectedSidebar === SidebarType.Components || selectedSidebar === SidebarType.Symbols;
  const isRightSidebarOpenExpanded = selectedSidebar === SidebarType.ComponentsExpanded || selectedSidebar === SidebarType.SymbolsExpanded;

  const isLeftSidebarOpenClasses = new Set<string>([
    'left-sidebar',
    'left-16',
    '-bottom-full',
    'md:-left-64',
    'md:bottom-0'
  ]);

  let isRightSidebarOpenClasses = 'right-0 -bottom-full md:-right-80 md:bottom-0';

  let marginSidebar = BAR_WIDTH;
  const viewerMarginClasses = new Set<string>([
    'ml-16'
  ]);

  if (isLeftSidebarOpen) {
    isLeftSidebarOpenClasses.delete('-bottom-full');
    isLeftSidebarOpenClasses.delete('md:-left-64');
    isLeftSidebarOpenClasses.delete('md:bottom-0');
    marginSidebar += 256;
    viewerMarginClasses.add(' md:ml-80');
  }

  if (isRightSidebarOpen || isRightSidebarOpenExpanded) {
    isRightSidebarOpenClasses = 'right-0';

    if (isRightSidebarOpenExpanded) {
      viewerMarginClasses.add(' md:mr-[32rem]');
      marginSidebar += 512;
    } else {
      viewerMarginClasses.add(' md:mr-64');
      marginSidebar += 256;
    }
  } else {
    isLeftSidebarOpenClasses.delete('left-sidebar');
    isLeftSidebarOpenClasses.add('left-sidebar-single');
  }

  const clickRestrictionsClasses = replaceContainer.isReplacing ? 'pointer-events-none opacity-50' : '';
  const isComponentsOpen = selectedSidebar === SidebarType.Components || selectedSidebar === SidebarType.ComponentsExpanded;
  const isSymbolsOpen = selectedSidebar === SidebarType.Symbols || selectedSidebar === SidebarType.SymbolsExpanded;

  return (
    <>
      <Bar
        className={clickRestrictionsClasses}
        isComponentsOpen={isComponentsOpen}
        isSymbolsOpen={isSymbolsOpen}
        isHistoryOpen={selectedSidebar === SidebarType.History}
        isMessagesOpen={selectedSidebar === SidebarType.Messages}
        isSettingsOpen={selectedSidebar === SidebarType.Settings}
        toggleComponents={() => {
          if (selectedSidebar === SidebarType.ComponentsExpanded) {
            setOrToggleSidebar(SidebarType.ComponentsExpanded);
          } else {
            setOrToggleSidebar(SidebarType.Components);
          }
        } }
        toggleSymbols={() => {
          if (selectedSidebar === SidebarType.SymbolsExpanded) {
            setOrToggleSidebar(SidebarType.SymbolsExpanded);
          } else {
            setOrToggleSidebar(SidebarType.Symbols);
          }
        } }
        toggleTimeline={() => {
          setOrToggleSidebar(SidebarType.History);
        } }
        toggleMessages={() => {
          setOrToggleSidebar(SidebarType.Messages);
        } }
        toggleSettings={() => {
          setOrToggleSidebar(SidebarType.Settings);
        } }
      />
      <Sidebar
        className={`${[...isLeftSidebarOpenClasses.values()].join(' ')}`}
        title={leftSidebarTitle}
      >
        { leftChildren }
      </Sidebar>
      <Viewer
        className={`${clickRestrictionsClasses} ${[...viewerMarginClasses.values()].join(' ')} w-full h-full`}
        current={current}
        isComponentsOpen={isComponentsOpen}
        isSymbolsOpen={isSymbolsOpen}
        selectedContainer={selectedContainer}
        selectContainer={methods.selectContainer}
        selectedSymbol={selectedSymbol}
        margin={marginSidebar}
      />
      <Sidebar
        className={`right-sidebar ${isRightSidebarOpenClasses} ${clickRestrictionsClasses}`}
        title={rightSidebarTitle}
      >
        { rightChildren }
      </Sidebar>
    </>
  );
}
