import React, { Dispatch, SetStateAction, useCallback, useContext, useEffect, useRef, useState } from 'react';
import { UseCustomEvents } from '../../Events/AppEvents';
import { MainMenu } from '../MainMenu/MainMenu';
import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel';
import { Editor } from '../Editor/Editor';
import { IEditorState } from '../../Interfaces/IEditorState';
import { LoadState } from './Actions/Load';
import { LoadEditor, NewEditor } from './Actions/MenuActions';
import { DEFAULT_CONFIG, DEFAULT_MAINCONTAINER_PROPS, FAST_BOOT } from '../../utils/default';
import { AppState } from '../../Enums/AppState';
import { Loader } from '../Loader/Loader';
import { LanguageContext } from '../LanguageProvider/LanguageProvider';

// App will never have props
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface IAppProps {
  root: Element | Document
}

function UseHTTPGETStatePreloading(
  appState: AppState,
  setEditorState: Dispatch<SetStateAction<IEditorState>>,
  setAppState: Dispatch<SetStateAction<AppState>>
): void {
  useEffect(() => {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString);
    const state = urlParams.get('state');

    if (state === null) {
      return;
    }

    if (appState !== AppState.Loaded) {
      fetch(state)
        .then(
          async(response) => await response.json(),
          (error) => { throw new Error(error); }
        )
        .then((data: IEditorState) => {
          LoadState(data, setEditorState, setAppState);
        }, (error) => { throw new Error(error); });
    }
  });
};

export function App(props: IAppProps): JSX.Element {
  const [appState, setAppState] = useState<AppState>(FAST_BOOT);
  const appRef = useRef<HTMLDivElement>(null);
  const languageContext = useContext(LanguageContext);

  const defaultMainContainer = new ContainerModel(
    DEFAULT_MAINCONTAINER_PROPS
  );
  const containers = new Map<string, IContainerModel>();
  containers.set(defaultMainContainer.properties.id, defaultMainContainer);

  const [editorState, setEditorState] = useState<IEditorState>({
    configuration: DEFAULT_CONFIG,
    history: [{
      lastAction: '',
      mainContainer: defaultMainContainer.properties.id,
      containers,
      selectedContainerId: defaultMainContainer.properties.id,
      typeCounters: {},
      symbols: new Map(),
      selectedSymbolId: ''
    }],
    historyCurrentStep: 0
  });

  UseCustomEvents(
    props.root,
    appRef,
    languageContext,
    setEditorState,
    setAppState
  );

  UseHTTPGETStatePreloading(appState, setEditorState, setAppState);

  switch (appState) {
    case AppState.Loaded:
      return (
        <div
          ref={appRef}
          className='App'
        >
          <Editor
            root={props.root}
            configuration={editorState.configuration}
            history={editorState.history}
            historyCurrentStep={editorState.historyCurrentStep}
          />
        </div>
      );
    case AppState.Loading:
      return (
        <div
          ref={appRef}
          className='App mainmenu-bg'
        >
          <div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
            <Loader />
          </div>
        </div>
      );
    default:
      return (
        <div
          ref={appRef}
          className='App mainmenu-bg'
        >
          <MainMenu
            newEditor={() => {
              setAppState(AppState.Loading);
              NewEditor(
                editorState,
                (newEditor) => setEditorState(newEditor),
                () => setAppState(AppState.Loaded)
              );
            }}
            loadEditor={(files: FileList | null) => LoadEditor(
              files,
              setEditorState,
              setAppState
            )}
          />
        </div>
      );
  }
};
