"use client";

/**
 * ErrorBoundary 组件（ai14，P6 硬化）
 *
 * 捕获子树 React 渲染异常，展示友好错误页并提供"重新加载"。
 * 若 Sentry 已初始化（见 lib/observability/sentry.ts），自动上报异常。
 */

import { Component, type ErrorInfo, type ReactNode } from "react";

export interface ErrorBoundaryProps {
  children: ReactNode;
  /** 自定义兜底 UI（可选） */
  fallback?: ReactNode;
}

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

export class ErrorBoundary extends Component<
  ErrorBoundaryProps,
  ErrorBoundaryState
> {
  override state: ErrorBoundaryState = { hasError: false, error: null };

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

  override componentDidCatch(error: Error, info: ErrorInfo): void {
    // 上报到 Sentry（若已初始化会在 window 上挂载捕获器）
    if (typeof window !== "undefined") {
      const capture = (
        window as unknown as {
          __eduCaptureException?: (e: Error, extra?: unknown) => void;
        }
      ).__eduCaptureException;
      capture?.(error, { componentStack: info.componentStack });
    }
    // 控制台兜底日志
    if (typeof console !== "undefined") {
      console.error("[student-portal] 渲染异常:", error, info);
    }
  }

  private handleReload = (): void => {
    if (typeof window !== "undefined") {
      window.location.reload();
    }
  };

  override render(): ReactNode {
    if (!this.state.hasError) {
      return this.props.children;
    }
    if (this.props.fallback) {
      return this.props.fallback;
    }
    return (
      <main
        className="min-h-screen flex items-center justify-center p-xl"
        role="alert"
        aria-live="assertive"
      >
        <section className="card-paper p-xl max-w-lg w-full text-center">
          <div className="mark-left py-md px-md text-left mb-lg">
            <h1 className="font-serif text-2xl text-ink">页面出现错误</h1>
            <p className="mt-sm text-sm text-ink-muted">
              抱歉，页面渲染时出现异常，请尝试重新加载。
            </p>
            {this.state.error?.message ? (
              <p className="mt-sm text-xs text-ink-subtle font-mono">
                {this.state.error.message}
              </p>
            ) : null}
          </div>
          <button
            type="button"
            className="btn-primary"
            onClick={this.handleReload}
          >
            重新加载
          </button>
        </section>
      </main>
    );
  }
}

export default ErrorBoundary;
