// @design-system: feedback/ErrorBoundary
/**
 * ErrorBoundary - React error boundary.
 *
 * Catches errors from the subtree and renders <ErrorState> with a retry button.
 * Strings pulled from `error` and `common` i18n namespaces at render time.
 *
 * Note: Error boundaries must be class components per React spec.
 * A thin functional wrapper reads locale from the prefs store and passes it
 * as a prop so the class component can use the correct language.
 *
 * @example
 * <ErrorBoundary>
 *   <SomeIsland />
 * </ErrorBoundary>
 */

import { Component, type ReactNode, type ErrorInfo } from 'react';
import { ErrorState } from '../ErrorState';
import { getT } from '@/lib/i18n';
import { captureCaught } from '@/lib/observability';
import { usePrefsStore } from '@/lib/i18n/store';
import type { Locale } from '@/lib/i18n';

interface Props {
  children: ReactNode;
  /** Override the error state rendered on failure. */
  fallback?: ReactNode;
}

interface InnerProps extends Props {
  locale: Locale;
}

interface State {
  hasError: boolean;
  error?: Error;
}

class ErrorBoundaryInner extends Component<InnerProps, State> {
  constructor(props: InnerProps) {
    super(props);
    this.state = { hasError: false };
  }

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

  override componentDidCatch(error: Error, info: ErrorInfo) {
    if (typeof window !== 'undefined' && import.meta.env.MODE !== 'test') {
      console.error('[ErrorBoundary]', error, info.componentStack);
      captureCaught(error, {
        scope: 'ui.error-boundary',
        severity: 'error',
        extra: { componentStack: info.componentStack },
      });
    }
  }

  handleRetry = () => {
    this.setState({ hasError: false, error: undefined });
  };

  override render() {
    if (this.state.hasError) {
      if (this.props.fallback) {
        return this.props.fallback;
      }

      const tError = getT(this.props.locale, 'error');
      const tCommon = getT(this.props.locale, 'common');

      return (
        <ErrorState
          title={tError('title')}
          description={tError('description')}
          action={
            <button
              type="button"
              onClick={this.handleRetry}
              className="text-text-secondary hover:bg-surface-inset border-border-default rounded-md border px-4 py-2 text-sm font-medium transition-colors duration-[var(--duration-fast)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
            >
              {tCommon('retry')}
            </button>
          }
        />
      );
    }

    return this.props.children;
  }
}

export function ErrorBoundary({ children, fallback }: Props) {
  const locale = usePrefsStore((s) => s.locale);
  return (
    <ErrorBoundaryInner locale={locale} fallback={fallback}>
      {children}
    </ErrorBoundaryInner>
  );
}
