'use client';

import * as Sentry from '@sentry/nextjs';
import { Component, type ErrorInfo, type ReactNode } from 'react';

export interface ErrorBoundaryFallbackProps {
  error: Error;
  reset: () => void;
}

export interface ErrorBoundaryProps {
  children: ReactNode;
  /** Custom fallback component. Receives the caught error and a reset callback. */
  fallback?: (props: ErrorBoundaryFallbackProps) => ReactNode;
  /** Called when an error is caught. Useful for additional logging / side effects. */
  onError?: (error: Error, info: ErrorInfo) => void;
}

interface ErrorBoundaryState {
  error: Error | null;
}

/**
 * Generic class-based React Error Boundary.
 *
 * Captures exceptions via Sentry and renders a Vietnamese-language fallback UI
 * with a "Thử lại" (retry) button when no custom fallback is provided.
 */
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
  override state: ErrorBoundaryState = { error: null };

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

  override componentDidCatch(error: Error, info: ErrorInfo) {
    Sentry.captureException(error, { extra: { componentStack: info.componentStack } });

    if (process.env.NODE_ENV !== 'production') {
      console.error('[ErrorBoundary] caught:', error, info);
    }

    this.props.onError?.(error, info);
  }

  reset = () => {
    this.setState({ error: null });
  };

  override render() {
    const { error } = this.state;
    const { children, fallback } = this.props;

    if (error) {
      if (fallback) {
        return fallback({ error, reset: this.reset });
      }
      return <DefaultErrorFallback error={error} reset={this.reset} />;
    }

    return children;
  }
}

function DefaultErrorFallback({ error, reset }: ErrorBoundaryFallbackProps) {
  return (
    <div
      className="flex min-h-[200px] flex-col items-center justify-center rounded-lg border border-destructive/20 bg-destructive/5 px-6 py-8 text-center"
      role="alert"
    >
      <svg
        className="mx-auto mb-3 h-8 w-8 text-destructive"
        fill="none"
        stroke="currentColor"
        viewBox="0 0 24 24"
        aria-hidden="true"
      >
        <path
          strokeLinecap="round"
          strokeLinejoin="round"
          strokeWidth={2}
          d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"
        />
      </svg>
      <p className="text-sm font-medium text-foreground">Đã xảy ra lỗi</p>
      {process.env.NODE_ENV !== 'production' && error.message && (
        <p className="mt-1 max-w-xs truncate text-xs text-muted-foreground">{error.message}</p>
      )}
      <button
        onClick={reset}
        className="mt-4 inline-flex h-9 items-center justify-center rounded-md bg-primary px-5 text-sm font-medium text-primary-foreground shadow transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
      >
        Thử lại
      </button>
    </div>
  );
}
