import React, { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react';
import { events as EVENTS } from '../../Events/AppEvents';
import { MainMenu } from '../MainMenu/MainMenu';
import { ContainerModel } 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 } from '../../utils/default';

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

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

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

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

function UseCustomEvents(
  root: Element | Document,
  appRef: React.RefObject<HTMLDivElement>,
  setEditor: (newState: IEditorState) => void,
  setLoaded: (loaded: boolean) => void
): void {
  useEffect(() => {
    const funcs = new Map<string, () => void>();
    for (const event of EVENTS) {
      function Func(eventInitDict?: CustomEventInit): void {
        return event.func(
          root,
          setEditor,
          setLoaded,
          eventInitDict
        );
      }
      appRef.current?.addEventListener(event.name, Func);
      funcs.set(event.name, Func);
    }
    return () => {
      for (const event of EVENTS) {
        const func = funcs.get(event.name);
        if (func === undefined) {
          continue;
        }
        appRef.current?.removeEventListener(event.name, func);
      }
    };
  });
}

export function App(props: IAppProps): JSX.Element {
  const [isLoaded, setLoaded] = useState<boolean>(false);
  const appRef = useRef<HTMLDivElement>(null);

  const defaultMainContainer = new ContainerModel(
    null,
    DEFAULT_MAINCONTAINER_PROPS
  );

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

  UseCustomEvents(
    props.root,
    appRef,
    setEditorState,
    setLoaded
  );

  UseHTTPGETStatePreloading(isLoaded, setEditorState, setLoaded);

  if (isLoaded) {
    return (
      <div
        ref={appRef}
        className='App'
      >
        <Editor
          root={props.root}
          configuration={editorState.configuration}
          history={editorState.history}
          historyCurrentStep={editorState.historyCurrentStep}
        />
      </div>
    );
  }

  return (
    <div
      ref={appRef}
      className='App mainmenu-bg'
    >
      <MainMenu
        newEditor={() => NewEditor(
          setEditorState, setLoaded
        )}
        loadEditor={(files: FileList | null) => LoadEditor(
          files,
          setEditorState,
          setLoaded
        )}
      />
    </div>
  );
};
