import { Component, type ErrorInfo, type ReactNode } from 'react';
import * as Sentry from '@sentry/react';
import { logger, getLogContext } from '@/utils/logger';
import { ErrorDisplay } from '@/components/ui/ErrorDisplay';

interface Props {
  children: ReactNode;
  fallback?: ReactNode;
}

interface State {
  hasError: boolean;
  error?: Error;
  errorInfo?: ErrorInfo;
}

export class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false };
  }

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

  override componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    this.setState({
      error,
      errorInfo,
    });

    // Action 3.3.1.4: Enhanced error boundary logging for monitoring
    const logContext = getLogContext();

    // Gather additional context for monitoring
    const monitoringContext = {
      ...logContext,
      component: 'ErrorBoundary',
      errorType: error.name || 'Error',
      errorMessage: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack,
      url: typeof window !== 'undefined' ? window.location.href : undefined,
      userAgent:
        typeof navigator !== 'undefined' ? navigator.userAgent : undefined,
      timestamp: new Date().toISOString(),
    };

    // Log to structured logger
    logger.error('[ErrorBoundary] React error caught', monitoringContext);

    // Send to Sentry with enriched context
    if (typeof window !== 'undefined') {
      Sentry.captureException(error, {
        contexts: {
          react: {
            componentStack: errorInfo.componentStack,
          },
          application: {
            ...logContext,
            url: window.location.href,
            userAgent: navigator.userAgent,
          },
        },
        tags: {
          error_boundary: true,
          error_type: error.name || 'Error',
          ...(logContext.request_id
            ? { request_id: String(logContext.request_id) }
            : {}),
        },
        level: 'error',
      });
    }
  }

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

  override render() {
    if (this.state.hasError) {
      if (this.props.fallback) {
        return this.props.fallback;
      }

      // Action 3.3.1.3: Use ErrorDisplay component for consistent error presentation
      return (
        <div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 p-4">
          <div className="w-full max-w-md">
            <ErrorDisplay
              error={
                this.state.error ||
                new Error("Une erreur inattendue s'est produite")
              }
              variant="card"
              severity="error"
              size="lg"
              showDetails={import.meta.env.DEV}
              context={{
                component: 'ErrorBoundary',
                action: 'rendering component',
                componentStack: this.state.errorInfo?.componentStack,
              }}
              onRetry={this.handleReset}
              actions={[
                {
                  label: "Retour à l'accueil",
                  onClick: () => {
                    window.location.href = '/';
                  },
                  variant: 'outline',
                },
              ]}
            />
          </div>
        </div>
      );
    }

    return this.props.children;
  }
}
