import React, {
  ReactNode,
  createContext,
  useCallback,
  useContext,
  useMemo,
  useRef,
} from "react";

type PositionMeasurements = {
  bottom: number;
  centerX: number;
  centerY: number;
  left: number;
  right: number;
  top: number;
  componentId: string;
};

type ContextValueValue = { [componentId: string]: PositionMeasurements };
type ContextValue = {
  value: ContextValueValue;
  updateComponentsPositions: (
    componentId: string,
    currentPosition: PositionMeasurements | null
  ) => void;
};

const ReactContext = createContext<ContextValue>({
  value: {},
  updateComponentsPositions: () => {},
});

export function useScreenTrackedViewPositionsContext() {
  return useContext(ReactContext);
}

const Provider = ({ children }: { children: ReactNode }) => {
  const contextRef = useRef<ContextValueValue>({});

  const updateComponentsPositions = useCallback(
    (componentId: string, currentPosition) => {
      if (currentPosition) {
        contextRef.current[componentId] = currentPosition;
      } else {
        delete contextRef.current[componentId];
      }
    },
    []
  );

  return (
    <ReactContext.Provider
      value={useMemo(
        () => ({
          value: contextRef.current,
          updateComponentsPositions,
        }),
        []
      )}
    >
      {children}
    </ReactContext.Provider>
  );
};

function withProvider(Component) {
  return function withProvider(props) {
    return (
      <Provider>
        <Component {...props} />
      </Provider>
    );
  };
}

export const ScreenTrackedViewPositionsContext = {
  Provider,
  withProvider,
  ReactContext,
};
