import React, { useState, useEffect } from 'react';
import Center from '@arcblock/ux/lib/Center';
import { CircularProgress } from '@mui/material';

type ComponentType<P = any> = React.ComponentType<P>;
type LoaderFunction<T extends ComponentType> = () => Promise<{ default: T } | T>;

interface LazyComponentOptions {
  LoadingComponent?: React.ComponentType;
  ErrorComponent?: React.ComponentType<{ error: Error }>;
}

export function createLazyComponent<T extends ComponentType, P extends React.ComponentProps<T>>(
  loader: LoaderFunction<T>,
  options: LazyComponentOptions = {}
) {
  let loadPromise: Promise<T> | null = null;
  const {
    LoadingComponent = () => (
      <Center>
        <CircularProgress />
      </Center>
    ),
    ErrorComponent = ({ error }) => <div>Error: {error.message}</div>,
  } = options;

  const loadComponent = async () => {
    if (loadPromise) return loadPromise;

    try {
      loadPromise = loader().then((result) => ('default' in result ? result.default : result));
      return await loadPromise;
    } catch (error) {
      loadPromise = null;
      throw error;
    }
  };

  return function WrappedComponent(props: P) {
    const [Component, setComponent] = useState<T | null>(null);
    const [error, setError] = useState<Error | null>(null);

    useEffect(() => {
      loadComponent()
        .then((comp) => {
          setComponent(() => comp);
        })
        .catch((err) => {
          setError(err);
          console.error('Failed to load component:', err);
        });
    }, []);

    if (error) {
      return <ErrorComponent error={error} />;
    }

    if (!Component) {
      return <LoadingComponent />;
    }

    return <Component {...props} />;
  };
}
