import React, { Component, ErrorInfo, ReactNode } from "react";
import { mdiAlertCircle } from "@mdi/js";

import BaseIcon from "./BaseIcon";

type ErrorBoundaryProps = {
  children: ReactNode;
};

type ErrorBoundaryState = {
  hasError: boolean;
  error: Error | null;
  errorInfo: ErrorInfo | null;
  showStack: boolean;
};

class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
  constructor(props: ErrorBoundaryProps) {
    super(props);

    this.state = {
      hasError: false,
      error: null,
      errorInfo: null,
      showStack: false,
    };
  }

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

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    console.error("Error caught in boundary:", error, errorInfo);

    this.setState({
      errorInfo,
    });
  }

  toggleStack = () => {
    this.setState((prevState) => ({
      showStack: !prevState.showStack,
    }));
  };

  resetError = () => {
    this.setState({
      hasError: false,
      error: null,
      errorInfo: null,
      showStack: false,
    });
  };

  render() {
    if (!this.state.hasError) {
      return this.props.children;
    }

    const { error, errorInfo, showStack } = this.state;
    const errorMessage = error?.message || "An unexpected error occurred";
    const stackTrace =
      errorInfo?.componentStack || error?.stack || "No stack trace available";

    return (
      <div className="flex min-h-screen items-center justify-center bg-slate-100 p-6">
        <div className="w-full max-w-xl rounded-2xl border border-rose-200 bg-white p-8 shadow-sm">
          <div className="flex items-center gap-3">
            <div className="rounded-2xl bg-rose-50 p-3 text-rose-600">
              <BaseIcon path={mdiAlertCircle} size={28} />
            </div>
            <div>
              <h1 className="text-xl font-semibold text-slate-950">
                Something went wrong
              </h1>
              <p className="mt-1 text-sm text-slate-600">
                The app stopped on a visible frontend error.
              </p>
            </div>
          </div>

          <div className="mt-6 rounded-xl bg-rose-50 p-4 font-mono text-sm text-rose-800">
            {errorMessage}
          </div>

          {showStack && (
            <pre className="mt-4 max-h-72 overflow-auto rounded-xl bg-slate-950 p-4 text-xs text-slate-100">
              {stackTrace}
            </pre>
          )}

          <div className="mt-6 flex flex-wrap gap-3">
            <button
              type="button"
              onClick={this.resetError}
              className="rounded-xl bg-blue-600 px-4 py-2 text-sm font-semibold text-white hover:bg-blue-500"
            >
              Try again
            </button>
            <button
              type="button"
              onClick={this.toggleStack}
              className="rounded-xl border border-slate-200 px-4 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-50"
            >
              {showStack ? "Hide details" : "Show details"}
            </button>
          </div>
        </div>
      </div>
    );
  }
}

export default ErrorBoundary;
