/**
 * React error boundary component.
 *
 * Catches render-time exceptions in child components and shows a fallback UI.
 */
import React from "react";
import { Button, makeStyles, Text, tokens } from "@fluentui/react-components";

interface ErrorBoundaryState {
  hasError: boolean;
  errorMessage: string | null;
}

interface ErrorBoundaryProps {
  children: React.ReactNode;
}

interface ErrorBoundaryFallbackProps {
  message: string;
  onReload: () => void;
}

const useFallbackStyles = makeStyles({
  root: {
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    justifyContent: "center",
    minHeight: "100vh",
    padding: tokens.spacingVerticalL,
    textAlign: "center",
    gap: tokens.spacingVerticalM,
  },
  message: {
    maxWidth: "40rem",
  },
});

function ErrorBoundaryFallback({ message, onReload }: ErrorBoundaryFallbackProps): React.ReactElement {
  const styles = useFallbackStyles();

  return (
    <div className={styles.root} role="alert">
      <Text as="h1" size={700} weight="semibold">
        Something went wrong
      </Text>
      <Text size={300} className={styles.message}>
        {message}
      </Text>
      <Button appearance="primary" onClick={onReload}>
        Reload
      </Button>
    </div>
  );
}

export class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
  constructor(props: ErrorBoundaryProps) {
    super(props);
    this.state = { hasError: false, errorMessage: null };
  }

  static getDerivedStateFromError(error: Error): ErrorBoundaryState {
    return { hasError: true, errorMessage: error.message || "Unknown error" };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
    console.error("ErrorBoundary caught an error", { error, errorInfo });
  }

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

  render(): React.ReactNode {
    if (this.state.hasError) {
      return (
        <ErrorBoundaryFallback
          message={this.state.errorMessage ?? "Please try reloading the page."}
          onReload={this.handleReload}
        />
      );
    }

    return this.props.children;
  }
}
