import {
  Suspense,
  lazy,
  type ComponentType,
} from 'react';
import { LoadingSpinner } from '../loading-spinner';
import { logger } from '@/utils/logger';
import { LazyErrorFallback } from './LazyErrorFallback';
import { LazyErrorBoundary } from './LazyErrorBoundary';

function createLazyWithErrorHandling<T extends ComponentType<any>>(
  importFunc: () => Promise<{ default: T } | T>,
  pageName: string,
) {
  return importFunc()
    .then((module) => module as { default: T })
    .catch((err) => {
      const errorMessage = err instanceof Error ? err.message : String(err);
      logger.error('[LazyComponent] Failed to import lazy component', {
        pageName,
        error: errorMessage,
        stack: err instanceof Error ? err.stack : undefined,
      });
      return Promise.resolve({
        default: () => (
          <LazyErrorFallback
            pageName={pageName}
            error={err instanceof Error ? err : new Error(errorMessage)}
          />
        ),
      }) as unknown as Promise<{ default: T }>;
    });
}

export interface LazyComponentProps {
  fallback?: React.ReactNode;
}

export function createLazyComponent<T extends ComponentType<any>>(
  importFunc: () => Promise<any>,
  fallback?: React.ReactNode,
  pageName?: string,
) {
  const safeImportFunc = pageName
    ? () => createLazyWithErrorHandling(importFunc as () => Promise<{ default: T }>, pageName)
    : importFunc;

  const LazyComponent = lazy(safeImportFunc);

  return function WrappedLazyComponent(
    props: React.ComponentProps<T> & LazyComponentProps,
  ) {
    const { fallback: _fallback, ...componentProps } = props;
    const component = (
      <Suspense fallback={fallback ?? <LoadingSpinner />}>
        <LazyComponent {...componentProps} />
      </Suspense>
    );
    if (pageName) {
      return (
        <LazyErrorBoundary pageName={pageName}>{component}</LazyErrorBoundary>
      );
    }
    return component;
  };
}
