// from https://github.com/vadimdemedes/ink/blob/v6.8.0/examples/concurrent-suspense/concurrent-suspense.tsx
/** @jsxRuntime automatic */
/** @jsxImportSource npm:react@19 */
/** @jsxImportSourceTypes npm:@types/react@19 */
import {
  type FunctionComponent,
  Suspense,
  use,
  useEffect,
  useMemo,
  useState,
} from "npm:react@19";
import { Box, render, Text } from "npm:ink@6.8";
import { delay } from "jsr:@std/async@1/delay";

/** Simulated async data fetching with cache */
const cache = new Map<string, Promise<string>>();

const fetchData = (key: string, delayMs: number): Promise<string> => {
  {
    const promise = cache.get(key);
    if (promise) return promise;
  }

  const promise = delay(delayMs).then(() => `Data for "${key}" (fetched in ${delayMs}ms)`);

  cache.set(key, promise);
  return promise;
};

/** Component that suspends while fetching */
const DataItem: FunctionComponent<{ readonly dataPromise: Promise<string> }> = (
  {
    dataPromise,
  },
) => {
  const data = use(dataPromise);
  return (
    <Box marginLeft={2}>
      <Text color="green">{data}</Text>
    </Box>
  );
};

/** Loading fallback */
const Loading: FunctionComponent<{ readonly message: string }> = (
  { message },
) => (
  <Box marginLeft={2}>
    <Text color="yellow">{message}</Text>
  </Box>
);

/** Main app demonstrating concurrent suspense */
const App: FunctionComponent = () => {
  const fastPromise = useMemo(() => fetchData("fast", 200), []);
  const mediumPromise = useMemo(() => fetchData("medium", 800), []);
  const slowPromise = useMemo(() => fetchData("slow", 1500), []);

  const [dynamicPromise, setDynamicPromise] = useState<
    Promise<string> | null
  >();

  // Auto-trigger "show more" after 2 seconds
  useEffect(() => {
    const timer = setTimeout(() => {
      setDynamicPromise(fetchData("dynamic", 500));
    }, 2000);
    return () => {
      clearTimeout(timer);
    };
  }, []);

  return (
    <Box flexDirection="column">
      <Text bold underline>
        Concurrent Suspense Demo
      </Text>
      <Text dimColor>
        (With concurrent: true, Suspense re-renders automatically)
      </Text>
      <Box marginTop={1} />

      <Text>Medium data (800ms):</Text>
      <Suspense fallback={<Loading message="Loading medium data..." />}>
        <DataItem dataPromise={mediumPromise} />
      </Suspense>

      <Box marginTop={1} />

      <Text>Fast data (200ms):</Text>
      <Suspense fallback={<Loading message="Loading fast data..." />}>
        <DataItem dataPromise={fastPromise} />
      </Suspense>

      <Box marginTop={1} />

      <Text>Slow data (1500ms):</Text>
      <Suspense fallback={<Loading message="Loading slow data..." />}>
        <DataItem dataPromise={slowPromise} />
      </Suspense>

      {dynamicPromise && (
        <>
          <Box marginTop={1} />
          <Text>Dynamically added (500ms):</Text>
          <Suspense fallback={<Loading message="Loading dynamic data..." />}>
            <DataItem dataPromise={dynamicPromise} />
          </Suspense>
        </>
      )}
    </Box>
  );
};

// Render with concurrent mode enabled
render(<App />, { concurrent: true });
