/* oxlint-disable react/rules-of-hooks -- this module deliberately routes compiler caches between tap and React at runtime */
import React from "react";
import { isDevelopment } from "../core/helpers/env";
import { peekResourceFiber } from "../core/helpers/execution-context";
import { tapRef } from "../hooks/tap-ref";

const ReactRuntime = React as any;
const MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
const createMemoCache = (size: number): unknown[] =>
  new Array(size).fill(MEMO_CACHE_SENTINEL);

const cPolyfill = (size: number): unknown[] =>
  ReactRuntime.useMemo(() => {
    const cache = createMemoCache(size);
    (cache as any)[MEMO_CACHE_SENTINEL] = true;
    return cache;
  }, []);

export const c = (size: number): unknown[] => {
  if (peekResourceFiber() === null) {
    return (ReactRuntime.__COMPILER_RUNTIME?.c ?? cPolyfill)(size);
  }

  const cacheRef = tapRef<unknown[] | null>(null);
  if (cacheRef.current === null) {
    cacheRef.current = createMemoCache(size);
  } else if (isDevelopment && cacheRef.current.length !== size) {
    console.error(
      "Expected a constant size argument for each invocation of c(). " +
        "The previous cache was allocated with size " +
        `${cacheRef.current.length} but size ${size} was requested.`,
    );
  }
  return cacheRef.current;
};
