import { reaction } from 'mobx';
import * as React from 'react';
import { CtrProvider, FC, useDefaultProps } from 'react-default-props-context';
import { useStore } from 'src/app/components';
import { flags } from 'src/app/flags';
import { scrollIntoView } from 'src/app/utils';
import { MoveListT } from 'src/movelists/types';
import { MovesState } from 'src/moves/MovesState';
import { log } from 'src/utils/logging';
import { lookUp } from 'src/utils/utils';

type PropsT = React.PropsWithChildren<{}>;

type DefaultPropsT = {
  moveList: MoveListT;
  moveLists: Array<MoveListT>;
};

export const MovesStateProvider: FC<PropsT, DefaultPropsT> = (p: PropsT) => {
  const props = useDefaultProps<PropsT, DefaultPropsT>(p);
  const { navigationStore, moveListsStore, movesStore, profilingStore } =
    useStore();

  const createState = () => {
    return new MovesState({
      navigationStore: navigationStore,
      moveListsStore: moveListsStore,
      movesStore: movesStore,
      scrollIntoView: (moveId: string) =>
        scrollIntoView(document.getElementById(moveId)),
    });
  };

  const updateState = (state: MovesState) => {
    return reaction(
      () => ({
        inputMoves: props.moveList
          ? lookUp(
              props.moveList ? props.moveList.moves : [],
              movesStore.moveById
            ).filter((x) => !!x)
          : [],
        userProfile: profilingStore.userProfile,
        moveList: props.moveList,
        moveLists: props.moveLists,
      }),
      ({ inputMoves, userProfile, moveList, moveLists }) => {
        state.inputs.moves = inputMoves;
        state.inputs.userProfile = userProfile;
        state.inputs.moveList = moveList;
        state.inputs.moveLists = moveLists;
        if (flags.logStateProviders) {
          log('MovesState updated', state.getSummary());
        }
      },
      {
        fireImmediately: true,
      }
    );
  };

  const getDefaultProps = (state: MovesState) => {
    const movePrivateData = () => {
      const moveId = state.moves.highlight.id;
      return moveId ? movesStore.getOrCreatePrivateData(moveId) : undefined;
    };

    return {
      movesState: () => state,
      move: () => state.moves.highlight.item,
      movePrivateData: () => movePrivateData(),
      moves: () => state.outputs.movesDisplay,
      movesEditing: () => state.moves.editing,
      movesEditingPD: () => state.moves.editingPrivateData,
      movesHighlight: () => state.moves.highlight,
      movesSelection: () => state.moves.selection,
      movesDragAndDrop: () => state.moves.dragAndDrop,
      movesClipboard: () => state.clipboard,
      movesFiltering: () => state.moves.filtering,
      movesAddition: () => state.moves.addition,
      movesInsertion: () => state.moves.insertion,
      movesHandlerClick: () => state.handlerClick,
      movesHandlerSelectWithKeys: () => state.handlerSelectWithKeys,
    };
  };

  return (
    <CtrProvider
      createCtr={createState}
      updateCtr={updateState}
      destroyCtr={(state: MovesState) => state.destroy()}
      getDefaultProps={getDefaultProps}
    >
      {props.children}
    </CtrProvider>
  );
};
