import {
  cloneElement,
  createContext,
  useContext,
  useState,
  useMemo,
  useCallback,
} from 'react';

interface LayersContextInterface {
  show: (component: React.ReactElement, key?: string) => string;
  hide: (key: string) => void;
  reset: () => void;
}

export const LayersContext = createContext<LayersContextInterface | null>(null);

export const useLayers = () => {
  const context = useContext(LayersContext);
  if (context === null) {
    throw new Error('useLayers must be used within a LayersContext');
  }
  return context;
};

export const LayersProvider = (props: { children: React.ReactNode }) => {
  const [state, setState] = useState<Record<string, React.ReactElement>>({});

  const show = useCallback((component: React.ReactElement, key?: string) => {
    const stateKey = key || +new Date() + '';
    setState((state) => {
      return { ...state, [stateKey]: component };
    });
    return stateKey;
  }, []);

  const hide = useCallback((key: string) => {
    setState((state) => {
      const draft = { ...state };
      delete draft[key];
      return draft;
    });
  }, []);

  const reset = useCallback(() => {
    setState({});
  }, []);

  const value = useMemo(() => ({ show, hide, reset }), [show, hide, reset]);

  // TODO refactor rendering
  return (
    <LayersContext.Provider value={value}>
      {props.children}
      {Object.keys(state).map((key, i, keys) =>
        cloneElement(state[key], { uppermost: keys.length - 1 === i, key })
      )}
    </LayersContext.Provider>
  );
};
