import React from "react";
import { error, warning } from "../../dev-warning";
import { noop } from "../../empty";
import bindEvents from "../event-bindings/bind-events";
import { RbdInvariant } from "../../invariant";

// Lame that this is not in flow

export default class ErrorBoundary extends React.Component {
  callbacks = null;
  unbind = noop;

  componentDidMount() {
    this.unbind = bindEvents(window, [
      {
        eventName: "error",
        fn: this.onWindowError
      }
    ]);
  }

  componentDidCatch(err) {
    if (err instanceof RbdInvariant) {
      if (import.meta.env.DEV) {
        error(err.message);
      }
      this.setState({});
      return;
    }

    // throwing error for other error boundaries
    throw err;
  }

  componentWillUnmount() {
    this.unbind();
  }

  onWindowError = (event) => {
    const callbacks = this.getCallbacks();
    if (callbacks.isDragging()) {
      callbacks.tryAbort();
      warning(`
        An error was caught by our window 'error' event listener while a drag was occurring.
        The active drag has been aborted.
      `);
    }
    const err = event.error;
    if (err instanceof RbdInvariant) {
      // Marking the event as dealt with.
      // This will prevent any 'uncaught' error warnings in the console
      event.preventDefault();
      if (import.meta.env.DEV) {
        error(err.message);
      }
    }
  };
  getCallbacks = () => {
    if (!this.callbacks) {
       
      throw new Error("Unable to find AppCallbacks in <ErrorBoundary/>");
    }
    return this.callbacks;
  };
  setCallbacks = (callbacks) => {
    this.callbacks = callbacks;
  };

  render() {
    return this.props.children(this.setCallbacks);
  }
}
