'use client';

import React, { Component, ReactNode, useState } from 'react';
import { ApiError } from '@/lib/api/base/ApiError';
import { connectionMonitor } from '@/lib/api/base/ApiConnectionMonitor';
import { ErrorDisplay } from '@/components/shared/ErrorDisplay';
import { DevErrorPanel } from '@/components/shared/DevErrorPanel';

interface Props {
  children: ReactNode;
  fallback?: ReactNode;
  onError?: (error: ApiError) => void;
}

interface State {
  hasError: boolean;
  error: ApiError | null;
  isDev: boolean;
}

/**
 * Error Boundary for API-related errors
 * Catches errors from API calls and displays appropriate UI
 */
export class ApiErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      hasError: false,
      error: null,
      isDev: process.env.NODE_ENV === 'development',
    };
  }

  static getDerivedStateFromError(error: Error): State {
    // Only handle ApiError instances
    if (error instanceof ApiError) {
      return {
        hasError: true,
        error,
        isDev: process.env.NODE_ENV === 'development',
      };
    }
    // Re-throw non-API errors
    throw error;
  }

  componentDidCatch(error: Error): void {
    if (error instanceof ApiError) {
      // Report to connection monitor
      connectionMonitor.recordFailure(error);
      
      // Call custom error handler if provided
      if (this.props.onError) {
        this.props.onError(error);
      }

      // For connectivity errors in production, don't show error boundary UI
      // These are handled by the notification system
      if (error.isConnectivityIssue() && !this.state.isDev) {
        // Reset error state so boundary doesn't block UI
        setTimeout(() => this.resetError(), 100);
        return;
      }
    }
  }

  componentDidMount(): void {
    // Listen for connection status changes
    const monitor = connectionMonitor;
    
    monitor.on('disconnected', this.handleDisconnected);
    monitor.on('degraded', this.handleDegraded);
    monitor.on('connected', this.handleConnected);
  }

  componentWillUnmount(): void {
    const monitor = connectionMonitor;
    
    monitor.off('disconnected', this.handleDisconnected);
    monitor.off('degraded', this.handleDegraded);
    monitor.off('connected', this.handleConnected);
  }

  private handleDisconnected = (): void => {
    // Connection status handled by notification system
  };

  private handleDegraded = (): void => {
    // Connection status handled by notification system
  };

  private handleConnected = (): void => {
    // Connection status handled by notification system
  };

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

  render(): ReactNode {
    if (this.state.hasError && this.state.error) {
      if (this.props.fallback) {
        return this.props.fallback;
      }

      // Show different UI based on environment
      if (this.state.isDev) {
        return (
          <DevErrorPanel 
            error={this.state.error} 
            onReset={this.resetError}
          />
        );
      }

      return (
        <ErrorDisplay 
          error={this.state.error}
          onRetry={this.resetError}
        />
      );
    }

    return this.props.children;
  }
}

/**
 * Hook-based alternative for functional components
 */
export function useApiErrorBoundary() {
  const [error, setError] = useState<ApiError | null>(null);
  const [isDev] = useState(process.env.NODE_ENV === 'development');

  const handleError = (err: ApiError) => {
    setError(err);
  };

  const reset = () => {
    setError(null);
  };

  return {
    error,
    isDev,
    handleError,
    reset,
    ErrorBoundary: ({ children }: { children: ReactNode }) => (
      <ApiErrorBoundary onError={handleError}>
        {children}
      </ApiErrorBoundary>
    ),
  };
}