import * as React from "react";
import { View, findNodeHandle } from "react-native";

import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
import { MasterCellAsyncRenderManager } from "./MasterCellAsyncRenderManager";

const layoutMeasure = (viewRef, onMeasure) => {
  viewRef?.measureLayout?.(
    findNodeHandle(viewRef),
    (x, y, width, height) => {
      onMeasure({ width, height });
    },
    noop
  );
};

const regularMeasure = (viewRef, onMeasure) => {
  viewRef?.measure?.((x, y, width, height) => {
    onMeasure({ width, height });
  });
};

const measure = platformSelect({
  android: layoutMeasure,
  android_tv: layoutMeasure,
  default: regularMeasure,
});

type Dimensions = {
  width: Option<number>;
  height: Option<number>;
};

type Return = {
  emitAsyncElementRegistrate: () => void;
  emitAsyncElementLayout: () => void;
  onCellLayout: () => void;
  dimensions: Dimensions;
  resetDimensions: () => void;
};

const initialDimensions = () => ({
  width: undefined,
  height: undefined,
});

export const useAsyncRendering = (viewRef: React.RefObject<View>): Return => {
  const [dimensions, setDimensions] = React.useState(initialDimensions());

  const managerRef = React.useRef(
    new MasterCellAsyncRenderManager(() => {
      measure(viewRef?.current, ({ width, height }) => {
        setDimensions({
          width,
          height: Math.ceil(height),
        });
      });
    })
  );

  React.useEffect(() => {
    return managerRef.current.start();
  }, []);

  const resetDimensions = React.useCallback(() => {
    setDimensions(initialDimensions());
  }, []);

  return React.useMemo(
    () => ({
      emitAsyncElementRegistrate:
        managerRef.current?.emitAsyncElementRegistrate,
      emitAsyncElementLayout: managerRef.current.emitAsyncElementLayout,
      dimensions,
      onCellLayout: managerRef.current.onCellLayout,
      resetDimensions,
    }),
    [dimensions, resetDimensions]
  );
};
