import { memo, useEffect, useLayoutEffect, useReducer, useRef } from "react";
import { CompositeHookLifecycle } from "../core/lifecycle";
import type { LifecycleChild } from "../core/lifecycle";

type LifecycleHostProps = {
  children?: React.ReactNode;
  composite: CompositeHookLifecycle;
};

function LifecycleHostInner({ children, composite }: LifecycleHostProps) {
  const childRef = useRef<LifecycleChild | null>(null);

  const [version, dispatch] = useReducer((v: number, cb: () => boolean) => {
    childRef.current?.setVersion(v);
    return v + (cb() ? 1 : 0);
  }, composite.version);

  childRef.current?.setVersion(version);
  const render = childRef.current?.render();

  useLayoutEffect(() => {
    if (render) {
      childRef.current?.commit(render);
    }
  });

  useEffect(
    () =>
      composite.registerHost({
        dispatch,
        mount: (child) => {
          childRef.current = child;
        },
        unmount: () => {
          childRef.current = null;
        },
      }),
    [composite],
  );

  return children;
}

export const LifecycleHost = memo(LifecycleHostInner);
