import { Suspense, lazy, type ComponentType, Component, type ErrorInfo } from 'react';
import { LoadingSpinner } from './loading-spinner';
// import { ErrorBoundary } from '@/components/ErrorBoundary';
import { logger } from '@/utils/logger';
import { Button } from './button';
import { AlertTriangle, RefreshCw } from 'lucide-react';

// CRITIQUE FIX #16: Composant de fallback amélioré pour les erreurs de chargement lazy
function LazyErrorFallback({
  pageName,
  error,
  onRetry
}: {
  pageName: string;
  error?: Error;
  onRetry?: () => void;
}) {
  return (
    <div className="container mx-auto px-4 py-8">
      <div className="max-w-2xl mx-auto">
        <div className="flex items-center gap-3 mb-4">
          <AlertTriangle className="h-6 w-6 text-yellow-600" />
          <h1 className="text-2xl font-bold">{pageName}</h1>
        </div>
        <div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 text-yellow-700 dark:text-yellow-300 px-4 py-3 rounded-lg mb-4">
          <p className="font-medium mb-2">Failed to load {pageName}</p>
          {error && (
            <p className="text-sm opacity-75">
              {error.message || 'An error occurred while loading this page'}
            </p>
          )}
        </div>
        <div className="flex gap-3">
          {onRetry && (
            <Button onClick={onRetry} variant="outline" className="flex items-center gap-2">
              <RefreshCw className="h-4 w-4" />
              Retry
            </Button>
          )}
          <Button
            onClick={() => window.location.reload()}
            variant="default"
            className="flex items-center gap-2"
          >
            Refresh Page
          </Button>
        </div>
      </div>
    </div>
  );
}

// CRITIQUE FIX #16: ErrorBoundary spécifique pour les composants lazy
class LazyErrorBoundary extends Component<
  {
    children: React.ReactNode;
    pageName: string;
    onError?: (error: Error, errorInfo: ErrorInfo) => void;
  },
  { hasError: boolean; error?: Error }
> {
  constructor(props: { children: React.ReactNode; pageName: string; onError?: (error: Error, errorInfo: ErrorInfo) => void }) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error };
  }

  override componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    // CRITIQUE FIX #16: Logger l'erreur avec le logger centralisé au lieu de console.error
    logger.error('[LazyComponent] Failed to load lazy component', {
      pageName: this.props.pageName,
      error: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack,
    });

    if (this.props.onError) {
      this.props.onError(error, errorInfo);
    }
  }

  handleRetry = () => {
    this.setState({ hasError: false, error: undefined });
  };

  override render() {
    if (this.state.hasError) {
      return (
        <LazyErrorFallback
          pageName={this.props.pageName}
          error={this.state.error}
          onRetry={this.handleRetry}
        />
      );
    }

    return this.props.children;
  }
}

/**
 * LazyComponentProps - Propriétés pour les composants lazy créés
 * 
 * @interface LazyComponentProps
 */
interface LazyComponentProps {
  /**
   * Composant de fallback personnalisé à afficher pendant le chargement
   * Si non fourni, utilise LoadingSpinner par défaut
   */
  fallback?: React.ReactNode;
}

/**
 * createLazyComponent - Factory pour créer des composants lazy avec Suspense
 * 
 * Crée un composant lazy avec gestion automatique du Suspense et du fallback.
 * Utile pour le code splitting et le chargement à la demande des composants.
 * 
 * @template T - Type du composant à charger
 * @param {() => Promise<{ default: T }>} importFunc - Fonction d'import dynamique
 * @param {React.ReactNode} fallback - Composant de fallback (optionnel)
 * @returns {ComponentType} Composant wrapper avec Suspense intégré
 * 
 * @example
 * ```tsx
 * // Créer un composant lazy
 * const LazyDashboard = createLazyComponent(
 *   () => import('@/pages/DashboardPage').then(m => ({ default: m.DashboardPage }))
 * );
 * 
 * // Utiliser le composant lazy
 * <LazyDashboard fallback={<CustomLoader />} />
 * ```
 * 
 * @function
 */
// CRITIQUE FIX #16: Wrapper pour gérer les erreurs de chargement lazy de manière standardisée
function createLazyWithErrorHandling<T extends ComponentType<any>>(
  importFunc: () => Promise<{ default: T }>,
  pageName: string,
) {
  return importFunc().catch((err) => {
    // CRITIQUE FIX #16: Logger l'erreur avec le logger centralisé
    logger.error('[LazyComponent] Failed to import lazy component', {
      pageName,
      error: err instanceof Error ? err.message : String(err),
      stack: err instanceof Error ? err.stack : undefined,
    });


    // Retourner un composant d'erreur au lieu de laisser l'erreur se propager
    return Promise.resolve({
      default: () => <LazyErrorFallback pageName={pageName} error={err instanceof Error ? err : new Error(String(err))} />,
    }) as unknown as Promise<{ default: T }>;
  });
}

export function createLazyComponent<T extends ComponentType<any>>(
  importFunc: () => Promise<{ default: T }>,
  fallback?: React.ReactNode,
  pageName?: string,
) {
  // CRITIQUE FIX #16: Utiliser la fonction avec gestion d'erreur si pageName est fourni
  const safeImportFunc = pageName
    ? () => createLazyWithErrorHandling(importFunc, pageName)
    : importFunc;

  const LazyComponent = lazy(safeImportFunc);

  return function WrappedLazyComponent(
    props: React.ComponentProps<T> & LazyComponentProps,
  ) {
    // Extraire fallback des props pour ne pas le passer au composant lazy
    const { fallback: _fallback, ...componentProps } = props;

    // CRITIQUE FIX #16: Wrapper avec ErrorBoundary pour capturer les erreurs runtime
    const component = (
      <Suspense fallback={fallback || <LoadingSpinner />}>
        {/* @ts-expect-error - LazyComponent props are compatible but TypeScript can't infer it */}
        <LazyComponent {...componentProps} />
      </Suspense>
    );

    // Si pageName est fourni, wrapper avec LazyErrorBoundary
    if (pageName) {
      return (
        <LazyErrorBoundary pageName={pageName}>
          {component}
        </LazyErrorBoundary>
      );
    }

    return component;
  };
}

// Composants lazy communs
// CRITIQUE FIX #16: Ajouter pageName pour tous les composants lazy pour une meilleure gestion d'erreur
export const LazyDashboard = createLazyComponent(
  () => import('@/pages/DashboardPage').then((m) => ({ default: m.DashboardPage })),
  undefined,
  'Dashboard',
);
export const LazyChat = createLazyComponent(
  () => import('@/features/chat/pages/ChatPage').then((m) => ({ default: m.ChatPage })),
  undefined,
  'Chat',
);
// CRITIQUE FIX #16: Tous les composants lazy utilisent maintenant la gestion d'erreur standardisée
export const LazyLibrary = createLazyComponent(
  () => import('@/features/library/pages/LibraryPage').then((m) => ({ default: m.default })),
  undefined,
  'Library',
);
export const LazyProfile = createLazyComponent(
  () => import('@/pages/ProfilePage').then((m) => ({ default: m.ProfilePage })),
  undefined,
  'Profile',
);
export const LazySettings = createLazyComponent(
  () => import('@/features/settings/pages/SettingsPage').then((m) => ({ default: m.SettingsPage })),
  undefined,
  'Settings',
);
export const LazyLogin = createLazyComponent(
  () => import('@/pages/LoginPage').then((m) => ({ default: m.LoginPage })),
  undefined,
  'Login',
);
export const LazyRegister = createLazyComponent(
  () => import('@/pages/RegisterPage').then((m) => ({ default: m.RegisterPage })),
  undefined,
  'Register',
);
export const LazyForgotPassword = createLazyComponent(
  () => import('@/features/auth/pages/ForgotPasswordPage'),
  undefined,
  'Forgot Password',
);
export const LazyVerifyEmail = createLazyComponent(
  () => import('@/features/auth/pages/VerifyEmailPage'),
  undefined,
  'Verify Email',
);
export const LazyResetPassword = createLazyComponent(
  () => import('@/features/auth/pages/ResetPasswordPage'),
  undefined,
  'Reset Password',
);
export const LazySessions = createLazyComponent(
  () => import('@/features/auth/pages/SessionsPage'),
  undefined,
  'Sessions',
);
export const LazyNotFound = createLazyComponent(
  () => import('@/features/error/pages/NotFoundPage'),
  undefined,
  'Not Found',
);
export const LazyServerError = createLazyComponent(
  () => import('@/features/error/pages/ServerErrorPage'),
  undefined,
  'Server Error',
);
export const LazyUserProfile = createLazyComponent(
  () => import('@/features/profile/pages/UserProfilePage').then((m) => ({ default: m.UserProfilePage })),
  undefined,
  'User Profile',
);
export const LazyRoles = createLazyComponent(
  () => import('@/features/roles/pages/RolesPage').then((m) => ({ default: m.RolesPage })),
  undefined,
  'Roles',
);
export const LazyTrackDetail = createLazyComponent(
  () => import('@/features/tracks/pages/TrackDetailPage').then((m) => ({ default: m.TrackDetailPage })),
  undefined,
  'Track Detail',
);
export const LazyPlaylistRoutes = createLazyComponent(
  () => import('@/features/playlists/routes').then((m) => ({ default: m.PlaylistRoutes })),
  undefined,
  'Playlists',
);
export const LazySearch = createLazyComponent(
  () => import('@/pages/SearchPage').then((m) => ({ default: m.SearchPage })),
  undefined,
  'Search',
);
export const LazyNotifications = createLazyComponent(
  () => import('@/features/notifications/pages/NotificationsPage').then((m) => ({ default: m.NotificationsPage })),
  undefined,
  'Notifications',
);
export const LazyMarketplace = createLazyComponent(
  () => import('@/pages/marketplace/MarketplaceHome').then((m) => ({ default: m.MarketplaceHome })),
  undefined,
  'Marketplace',
);
export const LazyAnalytics = createLazyComponent(
  () => import('@/pages/AnalyticsPage').then((m) => ({ default: m.AnalyticsPage })),
  undefined,
  'Analytics',
);
export const LazyWebhooks = createLazyComponent(
  () => import('@/pages/WebhooksPage').then((m) => ({ default: m.WebhooksPage })),
  undefined,
  'Webhooks',
);
export const LazyAdminDashboard = createLazyComponent(
  () => import('@/pages/AdminDashboardPage').then((m) => ({ default: m.AdminDashboardPage })),
  undefined,
  'Admin Dashboard',
);

export const LazyDesignSystemDemo = createLazyComponent(
  () => import('@/pages/DesignSystemDemoPage').then((m) => ({ default: m.default })),
  undefined,
  'Design System Demo',
);
