import React, { Component, ErrorInfo, ReactNode } from 'react';

interface Props {
  children: ReactNode;
  fallback?: ReactNode;
  componentName?: string;
  onError?: (error: Error, errorInfo: ErrorInfo) => void;
  autoRecover?: boolean;
  maxRetries?: number;
}

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

class ErrorBoundary extends Component<Props, State> {
  public state: State = {
    hasError: false,
    retryCount: 0,
    isRecovering: false
  };

  private retryTimeout?: NodeJS.Timeout;
  private readonly maxRetries: number;

  constructor(props: Props) {
    super(props);
    this.maxRetries = props.maxRetries || 3;
  }

  public static getDerivedStateFromError(error: Error): Partial<State> {
    return { hasError: true, error };
  }

  public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    console.error('Uncaught error:', error, errorInfo);
    
    // Recharts 관련 오류인 경우 추가 정보 로깅
    if (this.isRechartsError(error)) {
      this.logRechartsError(error, errorInfo);
    }

    // 일반적인 React 오류 로깅
    this.logGeneralError(error, errorInfo);

    // 에러 콜백 호출
    if (this.props.onError) {
      this.props.onError(error, errorInfo);
    }

    this.setState({ errorInfo });

    // 자동 복구 로직
    if (this.props.autoRecover && this.state.retryCount < this.maxRetries) {
      this.scheduleAutoRecovery();
    }
  }

  private isRechartsError(error: Error): boolean {
    return error.message.includes('Invariant failed') || 
           error.stack?.includes('generateCategoricalChart') ||
           error.message.includes('Recharts') ||
           error.stack?.includes('recharts') ||
           error.message.includes('categorical') ||
           error.message.includes('chart');
  }

  private logRechartsError(error: Error, errorInfo: ErrorInfo) {
    console.error('🚨 Recharts 차트 오류 감지:', {
      error: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack,
      timestamp: new Date().toISOString(),
      userAgent: navigator.userAgent,
      url: window.location.href,
      componentName: this.props.componentName || 'Unknown',
      retryCount: this.state.retryCount
    });
    
    // 추가 디버깅 정보 수집
    this.logChartDebugInfo();
  }

  private logGeneralError(error: Error, errorInfo: ErrorInfo) {
    console.error('🔴 일반 오류 감지:', {
      error: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack,
      timestamp: new Date().toISOString(),
      componentName: this.props.componentName || 'Unknown',
      retryCount: this.state.retryCount
    });
  }

  private logChartDebugInfo() {
    try {
      // DOM에서 차트 관련 요소들 찾기
      const chartElements = document.querySelectorAll('[class*="recharts"]');
      console.log('📊 차트 요소 개수:', chartElements.length);
      
      // 데이터 관련 정보 수집
      const dataElements = document.querySelectorAll('[data-testid*="chart"]');
      console.log('📈 데이터 요소 개수:', dataElements.length);
      
      // 메모리 사용량 확인
      if ('memory' in performance) {
        console.log('💾 메모리 사용량:', (performance as any).memory);
      }

      // React DevTools 정보
      if ((window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__) {
        console.log('🔧 React DevTools 감지됨');
      }
    } catch (debugError) {
      console.error('디버깅 정보 수집 중 오류:', debugError);
    }
  }

  private scheduleAutoRecovery() {
    if (this.retryTimeout) {
      clearTimeout(this.retryTimeout);
    }

    const delay = Math.min(1000 * Math.pow(2, this.state.retryCount), 10000); // 지수 백오프, 최대 10초
    
    this.setState({ isRecovering: true });
    
    this.retryTimeout = setTimeout(() => {
      this.setState(prevState => ({
        hasError: false,
        error: undefined,
        errorInfo: undefined,
        retryCount: prevState.retryCount + 1,
        isRecovering: false
      }));
    }, delay);
  }

  private handleRetry = () => {
    this.setState(prevState => ({
      hasError: false,
      error: undefined,
      errorInfo: undefined,
      retryCount: prevState.retryCount + 1,
      isRecovering: false
    }));
  };

  private handleReload = () => {
    window.location.reload();
  };

  private getErrorMessage(): string {
    if (!this.state.error) return '알 수 없는 오류가 발생했습니다.';

    const error = this.state.error;
    
    // Recharts 관련 오류 메시지
    if (this.isRechartsError(error)) {
      return '차트 데이터 처리 중 오류가 발생했습니다.';
    }
    
    // 일반적인 React 오류
    if (error.message.includes('React')) {
      return '컴포넌트 렌더링 중 오류가 발생했습니다.';
    }

    // 네트워크 오류
    if (error.message.includes('Network') || error.message.includes('fetch')) {
      return '네트워크 연결에 문제가 있습니다.';
    }

    // 타입 오류
    if (error.message.includes('Type') || error.message.includes('undefined')) {
      return '데이터 형식에 문제가 있습니다.';
    }
    
    return error.message || '알 수 없는 오류가 발생했습니다.';
  }

  private getErrorDetails(): string {
    if (!this.state.error) return '';
    
    const error = this.state.error;
    
    if (this.isRechartsError(error)) {
      return '차트 라이브러리에서 데이터 구조를 처리할 수 없습니다. 데이터를 확인하거나 페이지를 새로고침해주세요.';
    }

    if (error.message.includes('Network') || error.message.includes('fetch')) {
      return '인터넷 연결을 확인하고 다시 시도해주세요.';
    }

    if (error.message.includes('Type') || error.message.includes('undefined')) {
      return '데이터 형식을 확인하고 다시 시도해주세요.';
    }
    
    return '페이지를 새로고침하거나 잠시 후 다시 시도해주세요.';
  }

  private getRetryMessage(): string {
    if (this.state.retryCount === 0) return '';
    
    if (this.state.isRecovering) {
      return `자동 복구 시도 중... (${this.state.retryCount}/${this.maxRetries})`;
    }
    
    return `재시도 횟수: ${this.state.retryCount}/${this.maxRetries}`;
  }

  public componentWillUnmount() {
    if (this.retryTimeout) {
      clearTimeout(this.retryTimeout);
    }
  }

  public render() {
    if (this.state.hasError) {
      return this.props.fallback || (
        <div className="min-h-screen flex items-center justify-center bg-gray-50">
          <div className="max-w-md w-full bg-white shadow-lg rounded-lg p-6">
            <div className="flex items-center justify-center w-12 h-12 mx-auto bg-red-100 rounded-full">
              <svg className="w-6 h-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
              </svg>
            </div>
            <div className="mt-4 text-center">
              <h3 className="text-lg font-medium text-gray-900">오류가 발생했습니다</h3>
              {this.props.componentName && (
                <p className="text-sm text-gray-500 mt-1">
                  컴포넌트: {this.props.componentName}
                </p>
              )}
              <p className="mt-2 text-sm text-gray-600 mb-2">
                {this.getErrorMessage()}
              </p>
              <p className="text-xs text-gray-500 mb-2">
                {this.getErrorDetails()}
              </p>
              {this.getRetryMessage() && (
                <p className="text-xs text-blue-600 mb-4">
                  {this.getRetryMessage()}
                </p>
              )}
              <div className="space-y-2">
                <button
                  onClick={this.handleRetry}
                  disabled={this.state.isRecovering}
                  className="w-full inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
                >
                  {this.state.isRecovering ? '복구 중...' : '다시 시도'}
                </button>
                <button
                  onClick={this.handleReload}
                  className="w-full inline-flex items-center justify-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
                >
                  페이지 새로고침
                </button>
              </div>
            </div>
          </div>
        </div>
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary; 