'use client';

import React, { Component, ReactNode, ErrorInfo } from 'react';
import { ApiError } from '@/lib/api/base/ApiError';
import { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';
import { DevErrorPanel } from './DevErrorPanel';
import { ErrorDisplay } from './ErrorDisplay';

interface Props {
  children: ReactNode;
  fallback?: ReactNode;
  onError?: (error: Error, errorInfo: ErrorInfo) => void;
  onReset?: () => void;
  /**
   * Whether to show the enhanced dev overlay
   */
  enableDevOverlay?: boolean;
  /**
   * Additional context to include with errors
   */
  context?: Record<string, unknown>;
}

interface State {
  hasError: boolean;
  error: Error | ApiError | null;
  errorInfo: ErrorInfo | null;
  isDev: boolean;
}

/**
 * Enhanced React Error Boundary with maximum developer transparency
 * Integrates with GlobalErrorHandler and provides detailed debugging info
 */
export class EnhancedErrorBoundary extends Component<Props, State> {
  private globalErrorHandler: ReturnType<typeof getGlobalErrorHandler>;

  constructor(props: Props) {
    super(props);
    this.state = {
      hasError: false,
      error: null,
      errorInfo: null,
      isDev: process.env.NODE_ENV === 'development',
    };
    this.globalErrorHandler = getGlobalErrorHandler();
  }

  static getDerivedStateFromError(error: Error): State {
    return {
      hasError: true,
      error,
      errorInfo: null,
      isDev: process.env.NODE_ENV === 'development',
    };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
    // Add to React error history
    const reactErrors = (window as any).__GRIDPILOT_REACT_ERRORS__ || [];
    reactErrors.push({
      error,
      errorInfo,
      timestamp: new Date().toISOString(),
      componentStack: errorInfo.componentStack,
    });
    (window as any).__GRIDPILOT_REACT_ERRORS__ = reactErrors;

    // Report to global error handler with enhanced context
    const enhancedContext = {
      ...this.props.context,
      source: 'react_error_boundary',
      componentStack: errorInfo.componentStack,
      reactVersion: React.version,
      componentName: this.getComponentName(errorInfo),
    };

    // Use global error handler for maximum transparency
    this.globalErrorHandler.report(error, enhancedContext);

    // Call custom error handler if provided
    if (this.props.onError) {
      this.props.onError(error, errorInfo);
    }

    // Show dev overlay if enabled
    if (this.props.enableDevOverlay && this.state.isDev) {
      // The global handler will show the overlay, but we can add additional React-specific info
      this.showReactDevOverlay(error, errorInfo);
    }

    // Log to console with maximum detail
    if (this.state.isDev) {
      this.logReactErrorWithMaximumDetail(error, errorInfo);
    }
  }

  componentDidMount(): void {
    // Initialize global error handler if not already done
    if (this.props.enableDevOverlay && this.state.isDev) {
      this.globalErrorHandler.initialize();
    }
  }

  componentWillUnmount(): void {
    // Clean up if needed
  }

  /**
   * Extract component name from error info
   */
  private getComponentName(errorInfo: ErrorInfo): string | undefined {
    try {
      const stack = errorInfo.componentStack;
      if (stack) {
        const match = stack.match(/at (\w+)/);
        return match ? match[1] : undefined;
      }
    } catch {
      // Ignore
    }
    return undefined;
  }

  /**
   * Show React-specific dev overlay
   */
  private showReactDevOverlay(error: Error, errorInfo: ErrorInfo): void {
    const existingOverlay = document.getElementById('gridpilot-react-overlay');
    if (existingOverlay) {
      this.updateReactDevOverlay(existingOverlay, error, errorInfo);
      return;
    }

    const overlay = document.createElement('div');
    overlay.id = 'gridpilot-react-overlay';
    overlay.style.cssText = `
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 90%;
      max-width: 800px;
      max-height: 80vh;
      background: #1a1a1a;
      color: #fff;
      font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
      font-size: 12px;
      z-index: 999998;
      overflow: auto;
      padding: 20px;
      border: 3px solid #ff6600;
      border-radius: 8px;
      box-shadow: 0 0 40px rgba(255, 102, 0, 0.6);
    `;

    this.updateReactDevOverlay(overlay, error, errorInfo);
    document.body.appendChild(overlay);

    // Add keyboard shortcut to dismiss
    const dismissHandler = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        overlay.remove();
        document.removeEventListener('keydown', dismissHandler);
      }
    };
    document.addEventListener('keydown', dismissHandler);
  }

  /**
   * Update React dev overlay
   */
  private updateReactDevOverlay(overlay: HTMLElement, error: Error, errorInfo: ErrorInfo): void {
    overlay.innerHTML = `
      <div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 15px;">
        <h2 style="color: #ff6600; margin: 0; font-size: 18px;">⚛️ React Component Error</h2>
        <button onclick="this.parentElement.parentElement.remove()" 
                style="background: #ff6600; color: white; border: none; padding: 6px 12px; cursor: pointer; border-radius: 4px; font-weight: bold;">
          CLOSE
        </button>
      </div>

      <div style="background: #000; padding: 12px; border-radius: 4px; margin-bottom: 15px; border-left: 3px solid #ff6600;">
        <div style="color: #ff6600; font-weight: bold; margin-bottom: 5px;">Error Message</div>
        <div style="color: #fff;">${error.message}</div>
      </div>

      <div style="background: #000; padding: 12px; border-radius: 4px; margin-bottom: 15px; border-left: 3px solid #00aaff;">
        <div style="color: #00aaff; font-weight: bold; margin-bottom: 5px;">Component Stack Trace</div>
        <pre style="margin: 0; white-space: pre-wrap; color: #888;">${errorInfo.componentStack || 'No component stack available'}</pre>
      </div>

      <div style="background: #000; padding: 12px; border-radius: 4px; margin-bottom: 15px; border-left: 3px solid #ffaa00;">
        <div style="color: #ffaa00; font-weight: bold; margin-bottom: 5px;">JavaScript Stack Trace</div>
        <pre style="margin: 0; white-space: pre-wrap; color: #888; overflow-x: auto;">${error.stack || 'No stack trace available'}</pre>
      </div>

      <div style="background: #000; padding: 12px; border-radius: 4px; margin-bottom: 15px; border-left: 3px solid #00ff88;">
        <div style="color: #00ff88; font-weight: bold; margin-bottom: 5px;">React Information</div>
        <div style="line-height: 1.6; color: #888;">
          <div>React Version: ${React.version}</div>
          <div>Error Boundary: Active</div>
          <div>Timestamp: ${new Date().toLocaleTimeString()}</div>
        </div>
      </div>

      <div style="background: #000; padding: 12px; border-radius: 4px; border-left: 3px solid #aa00ff;">
        <div style="color: #aa00ff; font-weight: bold; margin-bottom: 5px;">Quick Actions</div>
        <div style="display: flex; gap: 8px; flex-wrap: wrap;">
          <button onclick="navigator.clipboard.writeText(\`${error.message}\n\nComponent Stack:\n${errorInfo.componentStack}\n\nStack:\n${error.stack}\`)" 
                  style="background: #0066cc; color: white; border: none; padding: 6px 10px; cursor: pointer; border-radius: 4px; font-size: 11px;">
            📋 Copy Details
          </button>
          <button onclick="window.location.reload()" 
                  style="background: #cc6600; color: white; border: none; padding: 6px 10px; cursor: pointer; border-radius: 4px; font-size: 11px;">
            🔄 Reload
          </button>
        </div>
      </div>

      <div style="margin-top: 15px; padding: 10px; background: #222; border-radius: 4px; border-left: 3px solid #888; font-size: 11px; color: #888;">
        💡 This React error boundary caught a component rendering error. Check the console for additional details from the global error handler.
      </div>
    `;
  }

  /**
   * Log React error with maximum detail
   */
  private logReactErrorWithMaximumDetail(error: Error, errorInfo: ErrorInfo): void {
    console.groupCollapsed('%c[REACT ERROR BOUNDARY] Component Rendering Failed', 
      'color: #ff6600; font-weight: bold; font-size: 14px;'
    );

    console.log('Error Details:', {
      message: error.message,
      name: error.name,
      stack: error.stack,
    });

    console.log('Component Stack:', errorInfo.componentStack);

    console.log('React Context:', {
      reactVersion: React.version,
      component: this.getComponentName(errorInfo),
      timestamp: new Date().toISOString(),
    });

    console.log('Props:', this.props);
    console.log('State:', this.state);

    // Show component hierarchy if available
    try {
      const hierarchy = this.getComponentHierarchy();
      if (hierarchy) {
        console.log('Component Hierarchy:', hierarchy);
      }
    } catch {
      // Ignore hierarchy extraction errors
    }

    console.groupEnd();
  }

  /**
   * Attempt to extract component hierarchy (for debugging)
   */
  private getComponentHierarchy(): string | null {
    // This is a simplified version - in practice, you might want to use React DevTools
    // or other methods to get the full component tree
    return null;
  }

  resetError = (): void => {
    this.setState({ hasError: false, error: null, errorInfo: null });
    if (this.props.onReset) {
      this.props.onReset();
    }
  };

  render(): ReactNode {
    if (this.state.hasError && this.state.error) {
      if (this.props.fallback) {
        return this.props.fallback;
      }

      // Show different UI based on environment
      if (this.state.isDev) {
        return (
          <DevErrorPanel 
            error={this.state.error instanceof ApiError ? this.state.error : new ApiError(
              this.state.error.message,
              'UNKNOWN_ERROR',
              {
                timestamp: new Date().toISOString(),
                source: 'react_error_boundary',
              },
              this.state.error
            )}
            onReset={this.resetError}
          />
        );
      }

      return (
        <ErrorDisplay 
          error={this.state.error instanceof ApiError ? this.state.error : new ApiError(
            this.state.error.message,
            'UNKNOWN_ERROR',
            {
              timestamp: new Date().toISOString(),
              source: 'react_error_boundary',
            },
            this.state.error
          )}
          onRetry={this.resetError}
        />
      );
    }

    return this.props.children;
  }
}

/**
 * Hook-based alternative for functional components
 */
export function useEnhancedErrorBoundary() {
  const [error, setError] = React.useState<Error | ApiError | null>(null);
  const [errorInfo, setErrorInfo] = React.useState<ErrorInfo | null>(null);
  const [isDev] = React.useState(process.env.NODE_ENV === 'development');

  const handleError = (err: Error, info: ErrorInfo) => {
    setError(err);
    setErrorInfo(info);
    
    // Report to global handler
    const globalHandler = getGlobalErrorHandler();
    globalHandler.report(err, {
      source: 'react_hook_boundary',
      componentStack: info.componentStack,
    });
  };

  const reset = () => {
    setError(null);
    setErrorInfo(null);
  };

  return {
    error,
    errorInfo,
    isDev,
    handleError,
    reset,
    ErrorBoundary: ({ children, enableDevOverlay }: { children: ReactNode; enableDevOverlay?: boolean }) => (
      <EnhancedErrorBoundary 
        onError={handleError} 
        enableDevOverlay={enableDevOverlay}
      >
        {children}
      </EnhancedErrorBoundary>
    ),
  };
}

/**
 * Higher-order component wrapper for easy usage
 */
export function withEnhancedErrorBoundary<P extends object>(
  Component: React.ComponentType<P>,
  options: Omit<Props, 'children'> = {}
): React.FC<P> {
  return (props: P) => (
    <EnhancedErrorBoundary {...options}>
      <Component {...props} />
    </EnhancedErrorBoundary>
  );
}