import React from 'react';
import { View, Text, StyleSheet, Platform, TouchableOpacity, Linking } from 'react-native';
import { colors } from '@/constants/colors';
import { RefreshCw, AlertTriangle, WifiOff, ExternalLink } from 'lucide-react-native';

interface Props {
  children: React.ReactNode;
  onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
}

interface State {
  hasError: boolean;
  error: Error | null;
  isConnectionError: boolean;
  isNgrokError: boolean;
}

const IFRAME_ID = 'rork-web-preview';

const webTargetOrigins = [
  "http://localhost:3000",
  "https://rorkai.com",
  "https://rork.app",
];    

function sendErrorToIframeParent(error: any, errorInfo?: any) {
  if (Platform.OS === 'web' && typeof window !== 'undefined') {
    console.debug('Sending error to parent:', {
      error,
      errorInfo,
      referrer: document.referrer
    });

    const errorMessage = {
      type: 'ERROR',
      error: {
        message: error?.message || error?.toString() || 'Unknown error',
        stack: error?.stack,
        componentStack: errorInfo?.componentStack,
        timestamp: new Date().toISOString(),
      },
      iframeId: IFRAME_ID,
    };

    try {
      window.parent.postMessage(
        errorMessage,
        webTargetOrigins.includes(document.referrer) ? document.referrer : '*'
      );
    } catch (postMessageError) {
      console.error('Failed to send error to parent:', postMessageError);
    }
  }
}

if (Platform.OS === 'web' && typeof window !== 'undefined') {
  window.addEventListener('error', (event) => {
    event.preventDefault();
    const errorDetails = event.error ?? {
      message: event.message ?? 'Unknown error',
      filename: event.filename ?? 'Unknown file',
      lineno: event.lineno ?? 'Unknown line',
      colno: event.colno ?? 'Unknown column'
    };
    sendErrorToIframeParent(errorDetails);
  }, true);

  window.addEventListener('unhandledrejection', (event) => {
    event.preventDefault();
    sendErrorToIframeParent(event.reason);
  }, true);

  const originalConsoleError = console.error;
  console.error = (...args) => {
    sendErrorToIframeParent(args.join(' '));
    originalConsoleError.apply(console, args);
  };
}

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

  static getDerivedStateFromError(error: Error) {
    // Check if this is a connection error
    const isConnectionError = 
      error.message.includes('Network Error') ||
      error.message.includes('Failed to fetch') ||
      error.message.includes('Network request failed');
    
    // Specifically check for ngrok errors
    const isNgrokError = 
      error.message.includes('ERR_NGROK') || 
      (Platform.OS === 'web' && 
       typeof window !== 'undefined' && 
       window.location.href.includes('ERR_NGROK'));
    
    return { 
      hasError: true, 
      error,
      isConnectionError: isConnectionError || isNgrokError,
      isNgrokError
    };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    sendErrorToIframeParent(error, errorInfo);
    if (this.props.onError) {
      this.props.onError(error, errorInfo);
    }
  }
  
  handleReload = () => {
    if (Platform.OS === 'web' && typeof window !== 'undefined') {
      window.location.reload();
    } else {
      // Reset error state
      this.setState({ hasError: false, error: null, isConnectionError: false, isNgrokError: false });
    }
  };

  handleOpenDocs = () => {
    Linking.openURL('https://docs.expo.dev/more/expo-cli/#connection-issues');
  };

  render() {
    if (this.state.hasError) {
      if (this.state.isConnectionError) {
        return (
          <View style={styles.container}>
            <View style={styles.content}>
              <WifiOff size={48} color={colors.error} style={styles.icon} />
              <Text style={styles.title}>Connection Error</Text>
              <Text style={styles.subtitle}>
                {this.state.isNgrokError 
                  ? "The development server tunnel (ngrok) is offline (ERR_NGROK_3200)" 
                  : "Unable to connect to the server"}
              </Text>
              <Text style={styles.description}>
                This is likely due to the development server being offline or a network issue. Try:
              </Text>
              <View style={styles.bulletPoints}>
                <Text style={styles.bulletPoint}>• Checking your internet connection</Text>
                <Text style={styles.bulletPoint}>• Restarting the Expo development server</Text>
                <Text style={styles.bulletPoint}>• Run: npm run start (without --tunnel)</Text>
                <Text style={styles.bulletPoint}>• Or: npm run start-clear (to clear cache)</Text>
              </View>
              <View style={styles.buttonContainer}>
                <TouchableOpacity 
                  style={styles.reloadButton}
                  onPress={this.handleReload}
                >
                  <RefreshCw size={18} color="#FFFFFF" style={styles.buttonIcon} />
                  <Text style={styles.reloadButtonText}>Retry Connection</Text>
                </TouchableOpacity>
                
                <TouchableOpacity 
                  style={styles.docsButton}
                  onPress={this.handleOpenDocs}
                >
                  <ExternalLink size={18} color={colors.textLightGray} style={styles.buttonIcon} />
                  <Text style={styles.docsButtonText}>Expo Docs</Text>
                </TouchableOpacity>
              </View>
            </View>
          </View>
        );
      }
      
      return (
        <View style={styles.container}>
          <View style={styles.content}>
            <AlertTriangle size={48} color={colors.warning} style={styles.icon} />
            <Text style={styles.title}>Something went wrong</Text>
            <Text style={styles.subtitle}>{this.state.error?.message || "An unexpected error occurred"}</Text>
            {Platform.OS !== 'web' && (
              <Text style={styles.description}>
                Please check your device logs for more details.
              </Text>
            )}
            <TouchableOpacity 
              style={styles.reloadButton}
              onPress={this.handleReload}
            >
              <RefreshCw size={18} color="#FFFFFF" style={styles.buttonIcon} />
              <Text style={styles.reloadButtonText}>Reload App</Text>
            </TouchableOpacity>
          </View>
        </View>
      );
    }

    return this.props.children;
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: colors.bgBlack,
  },
  content: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    padding: 20,
  },
  icon: {
    marginBottom: 16,
  },
  title: {
    fontSize: 36,
    textAlign: 'center',
    fontWeight: 'bold',
    marginBottom: 8,
    color: colors.textWhite,
  },
  subtitle: {
    fontSize: 16,
    color: colors.textLightGray,
    marginBottom: 12,
    textAlign: 'center',
  },
  description: {
    fontSize: 14,
    color: colors.textLightGray,
    textAlign: 'center',
    marginTop: 8,
    marginBottom: 16,
  },
  bulletPoints: {
    alignSelf: 'flex-start',
    marginVertical: 16,
  },
  bulletPoint: {
    fontSize: 14,
    color: colors.textLightGray,
    marginBottom: 8,
  },
  buttonContainer: {
    flexDirection: 'column',
    gap: 12,
    alignItems: 'center',
    marginTop: 12,
  },
  reloadButton: {
    marginTop: 12,
    backgroundColor: colors.primary,
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderRadius: 8,
    flexDirection: 'row',
    alignItems: 'center',
  },
  docsButton: {
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderRadius: 8,
    flexDirection: 'row',
    alignItems: 'center',
    borderWidth: 1,
    borderColor: colors.textLightGray,
  },
  reloadButtonText: {
    color: colors.textWhite,
    fontSize: 16,
    fontWeight: 'bold',
  },
  docsButtonText: {
    color: colors.textLightGray,
    fontSize: 16,
    fontWeight: 'bold',
  },
  buttonIcon: {
    marginRight: 8,
  },
}); 

export default ErrorBoundary;