import * as React from 'react';
import { ElementsList } from '../ElementsList/ElementsList';
import { History } from '../History/History';
import { IAvailableContainer } from '../../Interfaces/IAvailableContainer';
import { IContainerModel } from '../../Interfaces/IContainerModel';
import { IHistoryState } from '../../Interfaces/IHistoryState';
import { Bar } from '../Bar/Bar';
import { IAvailableSymbol } from '../../Interfaces/IAvailableSymbol';
import { Symbols } from '../Symbols/Symbols';
import { SymbolsSidebar } from '../SymbolsList/SymbolsList';
import { PropertyType } from '../../Enums/PropertyType';
import { Messages } from '../Messages/Messages';
import { ICategory } from '../../Interfaces/ICategory';
import { Sidebar } from '../Sidebar/Sidebar';
import { Components } from '../Components/Components';
import { Viewer } from '../Viewer/Viewer';
import { Settings } from '../Settings/Settings';
import { IMessage } from '../../Interfaces/IMessage';
import { DISABLE_API } from '../../utils/default';
import { UseWorker, UseAsync } from './UseWorker';
import { FindContainerById } from '../../utils/itertools';

export interface IUIProps {
  selectedContainer: IContainerModel | undefined
  current: IHistoryState
  history: IHistoryState[]
  historyCurrentStep: number
  availableContainers: IAvailableContainer[]
  availableSymbols: IAvailableSymbol[]
  categories: ICategory[]
  selectContainer: (containerId: string) => void
  deleteContainer: (containerId: string) => void
  onPropertyChange: (key: string, value: string | number | boolean | number[], type?: PropertyType) => void
  addContainer: (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
}

export enum SidebarType {
  None,
  Components,
  Symbols,
  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(props: IUIProps): JSX.Element {
  const [selectedSidebar, setSelectedSidebar] = React.useState<SidebarType>(SidebarType.Components);
  const [messages, setMessages] = React.useState<IMessage[]>([]);

  // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
  if (window.Worker && !DISABLE_API) {
    UseWorker(
      props.current,
      setMessages
    );
  } else if (!DISABLE_API) {
    UseAsync(
      props.current,
      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(props.current.containers, props.current.mainContainer)

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

  switch (selectedSidebar) {
    case SidebarType.Components:
      leftSidebarTitle = 'Components';
      leftChildren = <Components
        selectedContainer={props.selectedContainer}
        componentOptions={props.availableContainers}
        categories={props.categories}
        buttonOnClick={props.addContainer}
      />;
      rightSidebarTitle = 'Elements';
      rightChildren = <ElementsList
        containers={props.current.containers}
        mainContainer={mainContainer}
        symbols={props.current.symbols}
        selectedContainer={props.selectedContainer}
        onPropertyChange={props.onPropertyChange}
        selectContainer={props.selectContainer}
        addContainer={props.addContainerAt}
      />;
      break;

    case SidebarType.Symbols:
      leftSidebarTitle = 'Symbols';
      leftChildren = <Symbols
        componentOptions={props.availableSymbols}
        buttonOnClick={props.addSymbol}
      />;
      rightSidebarTitle = 'Symbols';
      rightChildren = <SymbolsSidebar
        selectedSymbolId={props.current.selectedSymbolId}
        symbols={props.current.symbols}
        onPropertyChange={props.onSymbolPropertyChange}
        selectSymbol={props.selectSymbol}
      />;
      break;

    case SidebarType.History:
      leftSidebarTitle = 'Timeline';
      leftChildren = <History
        history={props.history}
        historyCurrentStep={props.historyCurrentStep}
        jumpTo={props.loadState}
      />;
      break;

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

    case SidebarType.Settings:
      leftSidebarTitle = 'Settings';
      leftChildren = <Settings
        saveEditorAsJSON={props.saveEditorAsJSON}
        saveEditorAsSVG={props.saveEditorAsSVG}
      />;
      break;
  }

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

  let 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';

  if (isLeftSidebarOpen) {
    isLeftSidebarOpenClasses.delete('-bottom-full');
    isLeftSidebarOpenClasses.delete('md:-left-64');
    isLeftSidebarOpenClasses.delete('md:bottom-0');
  }

  if (isRightSidebarOpen) {
    isRightSidebarOpenClasses = 'right-0';
  } else {
    isLeftSidebarOpenClasses.delete('left-sidebar');
    isLeftSidebarOpenClasses.add('left-sidebar-single');
  }

  return (
    <>
      <Bar
        isComponentsOpen={selectedSidebar === SidebarType.Components}
        isSymbolsOpen={selectedSidebar === SidebarType.Symbols}
        isHistoryOpen={selectedSidebar === SidebarType.History}
        isMessagesOpen={selectedSidebar === SidebarType.Messages}
        isSettingsOpen={selectedSidebar === SidebarType.Settings}
        toggleComponents={() => {
          setOrToggleSidebar(SidebarType.Components);
        } }
        toggleSymbols={() => {
          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
        isLeftSidebarOpen={isLeftSidebarOpen}
        isRightSidebarOpen={isRightSidebarOpen}
        current={props.current}
        selectedContainer={props.selectedContainer}
        selectContainer={props.selectContainer}
      />
      <Sidebar
        className={`right-sidebar ${isRightSidebarOpenClasses}`}
        title={rightSidebarTitle}
      >
        { rightChildren }
      </Sidebar>
    </>
  );
}
