import { requireOptionalNativeModule } from "expo-modules-core";
import React from "react";
import { Platform, StyleSheet, Text, View } from "react-native";

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

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

const IFRAME_ID = "rork-web-preview";

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

const BridgeModule = requireOptionalNativeModule("Bridge");

function sendErrorToIframeParent(error: any, errorInfo?: any) {
  const errorData = {
    message: error?.message || error?.toString() || "Unknown error",
    stack: error?.stack,
    componentStack: errorInfo?.componentStack,
    timestamp: new Date().toISOString(),
  };

  if (Platform.OS === "web" && typeof window !== "undefined") {
    console.debug("Sending error to parent via postMessage:", {
      error,
      errorInfo,
      referrer: document.referrer,
    });

    const errorMessage = {
      type: "ERROR",
      error: errorData,
      iframeId: IFRAME_ID,
    };

    try {
      window.parent.postMessage(
        errorMessage,
        webTargetOrigins.includes(document.referrer) ? document.referrer : "*",
      );
    } catch (postMessageError) {
      console.warn("Failed to send error to parent:", postMessageError);
    }
  } else if (Platform.OS !== "web" && BridgeModule) {
    BridgeModule?.sendMessage({
      type: "runtime-error",
      data: JSON.stringify(errorData),
    });
  }
}

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 RorkErrorBoundary extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

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

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    sendErrorToIframeParent(error, errorInfo);
    if (this.props.onError) {
      this.props.onError(error, errorInfo);
    }
  }

  render() {
    if (this.state.hasError) {
      return (
        <View style={styles.container}>
          <View style={styles.content}>
            <Text style={styles.title}>Something went wrong</Text>
            <Text style={styles.subtitle}>{this.state.error?.message}</Text>
            {Platform.OS !== "web" && (
              <Text style={styles.description}>
                Please check your device logs for more details.
              </Text>
            )}
          </View>
        </View>
      );
    }

    return this.props.children;
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
  },
  content: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    padding: 20,
  },
  title: {
    fontSize: 36,
    textAlign: "center",
    fontWeight: "bold",
    marginBottom: 8,
  },
  subtitle: {
    fontSize: 14,
    color: "#666",
    marginBottom: 12,
    textAlign: "center",
  },
  description: {
    fontSize: 14,
    color: "#666",
    textAlign: "center",
    marginTop: 8,
  },
});
