/**
 * @fileoverview Error Boundary component for the RAG chatbot system
 * @module core/providers/ErrorBoundary
 */

import React, { Component, ErrorInfo, ReactNode } from "react";
import type { ChatbotError } from "../contexts/ChatbotContext";
import { createChatbotError } from "../../utils";

interface Props {
  /** Child components */
  children: ReactNode;
  /** Custom fallback component */
  fallback?: ReactNode;
  /** Error callback */
  onError?: (error: ChatbotError, errorInfo: ErrorInfo) => void;
  /** Whether to show error details in development */
  showErrorDetails?: boolean;
}

interface State {
  /** Whether an error has occurred */
  hasError: boolean;
  /** The error that occurred */
  error: ChatbotError | null;
  /** Error boundary info */
  errorInfo: ErrorInfo | null;
}

/**
 * Error Boundary component for catching and handling React errors
 * in the chatbot system
 */
export class ChatbotErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      hasError: false,
      error: null,
      errorInfo: null,
    };
  }

  static getDerivedStateFromError(error: Error): Partial<State> {
    // Update state so the next render will show the fallback UI
    const chatbotError = createChatbotError(
      "REACT_ERROR_BOUNDARY",
      error.message || "An unexpected error occurred",
      {
        originalError: error,
        stack: error.stack,
      }
    );

    return {
      hasError: true,
      error: chatbotError,
    };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    const chatbotError = createChatbotError(
      "REACT_ERROR_BOUNDARY",
      error.message || "An unexpected error occurred",
      {
        originalError: error,
        stack: error.stack,
        componentStack: errorInfo.componentStack,
      }
    );

    this.setState({
      error: chatbotError,
      errorInfo,
    });

    // Call the error callback if provided
    this.props.onError?.(chatbotError, errorInfo);

    // Log error to console in development
    if (process.env.NODE_ENV === "development") {
      console.error("ChatbotErrorBoundary caught an error:", error, errorInfo);
    }
  }

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

  render() {
    const { showErrorDetails = process.env.NODE_ENV === "development" } =
      this.props;

    if (this.state.hasError) {
      // Custom fallback component
      if (this.props.fallback) {
        return this.props.fallback;
      }

      // Default error UI
      return (
        <div className="chatbot-error-boundary p-6 bg-red-50 border border-red-200 rounded-lg">
          <div className="flex items-center mb-4">
            <div className="flex-shrink-0">
              <svg
                className="h-5 w-5 text-red-400"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 20 20"
                fill="currentColor"
              >
                <path
                  fillRule="evenodd"
                  d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
                  clipRule="evenodd"
                />
              </svg>
            </div>
            <div className="ml-3">
              <h3 className="text-sm font-medium text-red-800">
                Chatbot Error
              </h3>
              <p className="text-sm text-red-700 mt-1">
                {this.state.error?.message || "An unexpected error occurred"}
              </p>
            </div>
          </div>

          {showErrorDetails && this.state.error?.details && (
            <details className="mb-4">
              <summary className="text-sm font-medium text-red-800 cursor-pointer">
                Error Details
              </summary>
              <pre className="mt-2 text-xs text-red-700 bg-red-100 p-2 rounded overflow-auto max-h-40">
                {JSON.stringify(this.state.error.details, null, 2)}
              </pre>
            </details>
          )}

          <div className="flex space-x-2">
            <button
              onClick={this.handleRetry}
              className="bg-red-600 text-white px-3 py-1 rounded text-sm hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500"
            >
              Try Again
            </button>
            <button
              onClick={() => window.location.reload()}
              className="bg-gray-600 text-white px-3 py-1 rounded text-sm hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500"
            >
              Reload Page
            </button>
          </div>
        </div>
      );
    }

    return this.props.children;
  }
}

/**
 * Hook for using error boundary in functional components
 */
export const useChatbotErrorHandler = () => {
  const [error, setError] = React.useState<ChatbotError | null>(null);

  const handleError = React.useCallback((error: ChatbotError) => {
    setError(error);
    console.error("Chatbot error:", error);
  }, []);

  const clearError = React.useCallback(() => {
    setError(null);
  }, []);

  return {
    error,
    handleError,
    clearError,
    hasError: error !== null,
  };
};

export default ChatbotErrorBoundary;
