"use client"

import type { JSX } from "react"
import { Component, type ErrorInfo, type ReactNode } from "react"
import { useTranslations } from "next-intl"
import { AlertCircle, RefreshCw } from "lucide-react"

import { Button } from "@/shared/components/ui/button"

interface BoundaryProps {
  children: ReactNode
  /** 自定义降级 UI（函数形式，优先级最高）。若提供则忽略 title/description/retryLabel */
  fallback?: (error: Error, reset: () => void) => ReactNode
  /** 渲染失败时的标题（已国际化，默认取 {namespace}.error.boundaryTitle） */
  title?: string
  /** 渲染失败时的描述（已国际化，默认取 {namespace}.error.boundaryDescription） */
  description?: string
  /** 重试按钮文案（已国际化，默认取 {namespace}.error.retry） */
  retryLabel?: string
  /** 错误回调（用于埋点/监控） */
  onError?: (error: Error, info: ErrorInfo) => void
}

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

/**
 * 组件级 Error Boundary（类组件实现，承载错误捕获能力）。
 * 不直接使用，请使用默认导出的函数式 `SectionErrorBoundary` 包装器以获得 i18n 支持。
 *
 * 支持两种降级形式：
 * 1. `fallback`（函数 `(error, reset) => ReactNode`）— 完全自定义降级 UI（优先级最高）
 * 2. `title` / `description` / `retryLabel` — 默认降级 UI + i18n 文案
 */
class SectionErrorBoundaryBase extends Component<BoundaryProps, State> {
  constructor(props: BoundaryProps) {
    super(props)
    this.state = { hasError: false, error: null }
  }

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

  componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
    console.error("[SectionErrorBoundary]", error, errorInfo)
    this.props.onError?.(error, errorInfo)
  }

  private handleRetry = (): void => {
    this.setState({ hasError: false, error: null })
  }

  render(): ReactNode {
    if (this.state.hasError && this.state.error) {
      // 优先使用自定义 fallback
      if (this.props.fallback) {
        return this.props.fallback(this.state.error, this.handleRetry)
      }
      // 默认降级 UI
      return (
        <div
          role="alert"
          aria-live="assertive"
          className="flex flex-col items-center justify-center space-y-3 rounded-lg border border-dashed p-8 text-center"
        >
          <AlertCircle className="h-8 w-8 text-muted-foreground" aria-hidden="true" />
          <div className="space-y-1">
            <p className="text-sm font-medium">
              {this.props.title ?? "加载失败"}
            </p>
            <p className="text-xs text-muted-foreground">
              {this.props.description ?? "数据加载时发生错误，请重试。"}
            </p>
          </div>
          <Button
            variant="outline"
            size="sm"
            onClick={this.handleRetry}
            aria-label={this.props.retryLabel ?? "重试"}
          >
            <RefreshCw className="mr-1.5 h-3.5 w-3.5" aria-hidden="true" />
            {this.props.retryLabel ?? "重试"}
          </Button>
        </div>
      )
    }
    return this.props.children
  }
}

interface SectionErrorBoundaryProps {
  children: ReactNode
  /** i18n namespace，默认 "common"。需保证该 namespace 下存在 error.boundaryTitle / error.boundaryDescription / error.retry 键 */
  namespace?: string
  /** 自定义降级 UI（函数形式，优先级最高）。若提供则忽略 title/description/retryLabel */
  fallback?: (error: Error, reset: () => void) => ReactNode
  /** 显式覆盖标题（优先级高于 i18n 默认） */
  title?: string
  /** 显式覆盖描述 */
  description?: string
  /** 显式覆盖重试按钮文案 */
  retryLabel?: string
  /** 错误回调（用于埋点/监控） */
  onError?: (error: Error, info: ErrorInfo) => void
}

/**
 * 组件级 Error Boundary：包裹独立数据区块，防止单区块错误导致整页崩溃。
 * 自动使用 next-intl 提供本地化文案；如需完全自定义可传入 `fallback` 函数。
 *
 * @example
 * ```tsx
 * // 默认 i18n 文案
 * <SectionErrorBoundary namespace="coursePlans">
 *   <CoursePlanProgress plan={plan} />
 * </SectionErrorBoundary>
 *
 * // 完全自定义降级 UI
 * <SectionErrorBoundary fallback={(error, reset) => <CustomUI error={error} onRetry={reset} />}>
 *   <CoursePlanProgress plan={plan} />
 * </SectionErrorBoundary>
 * ```
 */
export function SectionErrorBoundary({
  children,
  namespace = "common",
  fallback,
  title,
  description,
  retryLabel,
  onError,
}: SectionErrorBoundaryProps): JSX.Element {
  const t = useTranslations(namespace)
  return (
    <SectionErrorBoundaryBase
      fallback={fallback}
      title={title ?? t("error.boundaryTitle")}
      description={description ?? t("error.boundaryDescription")}
      retryLabel={retryLabel ?? t("error.retry")}
      onError={onError}
    >
      {children}
    </SectionErrorBoundaryBase>
  )
}
