import * as React from 'react';
import {
  AlertTriangle,
  AlertCircle,
  Info,
  X,
  ChevronDown,
  ChevronUp,
  Bug,
  Copy,
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { Button } from './button';
import { Card, CardContent } from './card';
import { Dialog } from './dialog';
import type { ApiError } from '@/schemas/apiSchemas';
import { formatUserFriendlyError } from '@/utils/errorMessages';
import { parseApiError, getErrorCategory } from '@/utils/apiErrorHandler';
import {
  formatIssueReport,
  copyIssueReportToClipboard,
  openGitHubIssue,
} from '@/utils/reportIssue';
// CRITICAL FIX: Utiliser le wrapper lazy pour éviter les collisions de noms de variables
import toast from '@/utils/toast';

/**
 * ErrorDisplayProps - Props for the ErrorDisplay component
 *
 * Standardizes error presentation across the application with support for
 * different variants, severities, and recovery actions.
 */
export interface ErrorDisplayProps {
  /**
   * The error to display
   * Can be Error object, ApiError, string, or error-like object
   */
  error:
    | Error
    | ApiError
    | string
    | {
        message: string;
        code?: string | number;
        status?: number;
        details?: Record<string, any>;
      };

  /**
   * Callback when user clicks retry button
   * If not provided, retry button is hidden
   */
  onRetry?: () => void | Promise<void>;

  /**
   * Callback when user dismisses the error
   * If not provided, dismiss button is hidden
   */
  onDismiss?: () => void;

  /**
   * Whether to show detailed error information
   * Default: false (only shows user-friendly message)
   * In development, defaults to true
   */
  showDetails?: boolean;

  /**
   * Additional context about where/why the error occurred
   * Used for logging and debugging
   */
  context?: {
    action?: string; // e.g., "fetching tracks", "uploading file"
    resource?: string; // e.g., "tracks", "playlist"
    resourceId?: string; // e.g., track ID, playlist ID
    [key: string]: any; // Additional context
  };

  /**
   * Variant/style of error display
   * - "inline": Inline error within content (default)
   * - "banner": Full-width banner at top of page
   * - "modal": Modal dialog overlay
   * - "card": Card-style error display
   */
  variant?: 'inline' | 'banner' | 'modal' | 'card';

  /**
   * Error severity/category
   * Affects visual styling (color, icon)
   * - "error": Critical errors (default)
   * - "warning": Warnings that don't block functionality
   * - "info": Informational messages
   */
  severity?: 'error' | 'warning' | 'info';

  /**
   * Size of the error display
   * - "sm": Small, compact
   * - "md": Medium (default)
   * - "lg": Large, prominent
   */
  size?: 'sm' | 'md' | 'lg';

  /**
   * Custom className for styling
   */
  className?: string;

  /**
   * Whether error is dismissible
   * Default: true (if onDismiss provided)
   */
  dismissible?: boolean;

  /**
   * Custom title override
   * If not provided, uses default title based on error type
   */
  title?: string;

  /**
   * Custom icon override
   * If not provided, uses default icon based on severity
   */
  icon?: React.ReactNode;

  /**
   * Additional actions to display alongside retry/dismiss
   * Array of { label, onClick, variant } objects
   */
  actions?: Array<{
    label: string;
    onClick: () => void;
    variant?: 'default' | 'outline' | 'ghost';
  }>;
}

/**
 * Normalizes different error types into a consistent structure
 */
function normalizeError(
  error:
    | Error
    | ApiError
    | string
    | {
        message: string;
        code?: string | number;
        status?: number;
        details?: Record<string, any>;
      },
): {
  message: string;
  code?: string | number;
  status?: number;
  details?: any;
  stack?: string;
} {
  // String error
  if (typeof error === 'string') {
    return { message: error };
  }

  // Standard Error object
  if (error instanceof Error) {
    return {
      message: error.message,
      stack: error.stack,
    };
  }

  // ApiError or error-like object
  if (error && typeof error === 'object') {
    // Try to parse as ApiError if it has the structure
    try {
      const apiError = parseApiError(error);
      return {
        message: apiError.message || 'An error occurred',
        code: apiError.code,
        status: typeof apiError.code === 'number' ? apiError.code : undefined,
        details: apiError.details,
      };
    } catch {
      // Fallback to direct object access
      return {
        message: (error as any).message || String(error),
        code: (error as any).code,
        status: (error as any).status,
        details: (error as any).details,
      };
    }
  }

  return { message: String(error) };
}

/**
 * ErrorDisplay - Standardized error display component
 *
 * Provides consistent error UI across the application with support for
 * different variants, severities, and recovery actions.
 *
 * @example
 * ```tsx
 * <ErrorDisplay
 *   error={error}
 *   onRetry={() => refetch()}
 * />
 * ```
 */
export const ErrorDisplay = React.forwardRef<HTMLDivElement, ErrorDisplayProps>(
  (
    {
      error,
      onRetry,
      onDismiss,
      showDetails: showDetailsProp,
      context,
      variant = 'inline',
      severity = 'error',
      size = 'md',
      className,
      dismissible,
      title: titleProp,
      icon: iconProp,
      actions = [],
      ...props
    },
    ref,
  ) => {
    const [isDetailsExpanded, setIsDetailsExpanded] = React.useState(false);
    const [isRetrying, setIsRetrying] = React.useState(false);
    const [isModalOpen, setIsModalOpen] = React.useState(true);

    // Normalize error
    const normalizedError = React.useMemo(() => normalizeError(error), [error]);

    // Parse error to ApiError for category detection
    const apiError = React.useMemo(() => parseApiError(error), [error]);
    const errorCategory = React.useMemo(
      () => getErrorCategory(apiError),
      [apiError],
    );

    // Determine if this is a server error that should show report issue button
    const isServerError = React.useMemo(() => {
      const normalized = normalizeError(error);
      return (
        errorCategory === 'server_error' ||
        (normalized.status !== undefined && normalized.status >= 500)
      );
    }, [errorCategory, error]);

    // Determine if details should be shown
    const isDev = import.meta.env.DEV;
    const showDetails = showDetailsProp ?? isDev;

    // Extract user-friendly message
    const userMessage = React.useMemo(() => {
      if (normalizedError.message) {
        // Try to format using utility if it's an ApiError-like structure
        try {
          return formatUserFriendlyError(
            normalizedError as ApiError,
            context?.resource as any,
            false,
          );
        } catch {
          return normalizedError.message;
        }
      }
      return 'An unexpected error occurred';
    }, [normalizedError, context]);

    // Determine title
    const title = React.useMemo(() => {
      if (titleProp) return titleProp;

      if (context?.action) {
        return `Error ${context.action}`;
      }

      switch (severity) {
        case 'error':
          return 'Error';
        case 'warning':
          return 'Warning';
        case 'info':
          return 'Information';
        default:
          return 'Error';
      }
    }, [titleProp, context, severity]);

    // Icon configuration
    const iconConfig = React.useMemo(() => {
      if (iconProp) return iconProp;

      const iconSize =
        size === 'sm' ? 'w-4 h-4' : size === 'lg' ? 'w-6 h-6' : 'w-5 h-5';

      switch (severity) {
        case 'error':
          return <AlertCircle className={cn(iconSize, 'text-kodo-red')} />;
        case 'warning':
          return <AlertTriangle className={cn(iconSize, 'text-kodo-gold')} />;
        case 'info':
          return <Info className={cn(iconSize, 'text-kodo-cyan')} />;
        default:
          return <AlertCircle className={cn(iconSize, 'text-kodo-red')} />;
      }
    }, [iconProp, severity, size]);

    // Color styles based on severity
    const colorStyles = React.useMemo(() => {
      switch (severity) {
        case 'error':
          return {
            bg: 'bg-kodo-red/10',
            border: 'border-kodo-red/30',
            text: 'text-kodo-red',
            icon: 'text-kodo-red',
          };
        case 'warning':
          return {
            bg: 'bg-kodo-gold/10',
            border: 'border-kodo-gold/30',
            text: 'text-kodo-gold',
            icon: 'text-kodo-gold',
          };
        case 'info':
          return {
            bg: 'bg-kodo-cyan/10',
            border: 'border-kodo-cyan/30',
            text: 'text-kodo-cyan',
            icon: 'text-kodo-cyan',
          };
        default:
          return {
            bg: 'bg-kodo-red/10',
            border: 'border-kodo-red/30',
            text: 'text-kodo-red',
            icon: 'text-kodo-red',
          };
      }
    }, [severity]);

    // Size styles
    const sizeStyles = React.useMemo(() => {
      switch (size) {
        case 'sm':
          return {
            padding: 'p-3',
            text: 'text-xs',
            title: 'text-sm',
            gap: 'gap-2',
          };
        case 'lg':
          return {
            padding: 'p-6',
            text: 'text-base',
            title: 'text-lg',
            gap: 'gap-4',
          };
        default:
          return {
            padding: 'p-4',
            text: 'text-sm',
            title: 'text-base',
            gap: 'gap-3',
          };
      }
    }, [size]);

    // Handle retry
    const handleRetry = React.useCallback(async () => {
      if (!onRetry || isRetrying) return;

      setIsRetrying(true);
      try {
        await onRetry();
      } finally {
        setIsRetrying(false);
      }
    }, [onRetry, isRetrying]);

    // Handle dismiss
    const handleDismiss = React.useCallback(() => {
      if (onDismiss) {
        onDismiss();
      }
      if (variant === 'modal') {
        setIsModalOpen(false);
      }
    }, [onDismiss, variant]);

    // Handle report issue
    const handleReportIssue = React.useCallback(async () => {
      try {
        const report = formatIssueReport(error, {
          component: context?.resource,
          action: context?.action,
          userId: context?.userId,
          additionalInfo: context,
        });

        // Try to open GitHub issue first, fallback to clipboard
        try {
          openGitHubIssue(report);
          toast.success('Opening GitHub issue...');
        } catch {
          // Fallback to clipboard
          await copyIssueReportToClipboard(report);
          toast.success('Issue report copied to clipboard');
        }
      } catch (err) {
        toast.error('Failed to generate issue report');
      }
    }, [error, context]);

    // Action 5.3.1.2: Copy request ID to clipboard
    const handleCopyRequestId = React.useCallback(async () => {
      if (!apiError.request_id) return;

      try {
        if (
          typeof navigator !== 'undefined' &&
          navigator.clipboard &&
          navigator.clipboard.writeText
        ) {
          await navigator.clipboard.writeText(apiError.request_id);
          toast.success('Request ID copied to clipboard');
        } else {
          // Fallback: create temporary textarea
          const textarea = document.createElement('textarea');
          textarea.value = apiError.request_id;
          textarea.style.position = 'fixed';
          textarea.style.opacity = '0';
          document.body.appendChild(textarea);
          textarea.select();
          try {
            document.execCommand('copy');
            toast.success('Request ID copied to clipboard');
          } finally {
            document.body.removeChild(textarea);
          }
        }
      } catch (err) {
        toast.error('Failed to copy request ID');
      }
    }, [apiError.request_id]);

    // Determine if dismissible
    const isDismissible =
      dismissible ?? (onDismiss !== undefined || variant === 'modal');

    // Render error details
    const renderDetails = () => {
      if (!showDetails || !isDetailsExpanded) return null;

      const details: Array<{ label: string; value: any }> = [];

      // Show request ID prominently for server errors
      if (apiError.request_id) {
        details.push({ label: 'Request ID', value: apiError.request_id });
      }
      if (normalizedError.code) {
        details.push({
          label: 'Error Code',
          value: String(normalizedError.code),
        });
      }
      if (normalizedError.status) {
        details.push({
          label: 'HTTP Status',
          value: String(normalizedError.status),
        });
      }
      if (normalizedError.details) {
        details.push({
          label: 'Details',
          value: JSON.stringify(normalizedError.details, null, 2),
        });
      }
      if (normalizedError.stack) {
        details.push({ label: 'Stack Trace', value: normalizedError.stack });
      }
      if (context) {
        details.push({
          label: 'Context',
          value: JSON.stringify(context, null, 2),
        });
      }

      if (details.length === 0) return null;

      return (
        <div className="mt-4 pt-4 border-t border-white/10">
          <div className="space-y-2">
            {details.map((detail, idx) => (
              <div key={idx} className="text-xs">
                <span className="font-semibold opacity-70">
                  {detail.label}:
                </span>
                <pre className="mt-1 p-2 bg-black/20 rounded text-xs overflow-x-auto">
                  {typeof detail.value === 'string'
                    ? detail.value
                    : JSON.stringify(detail.value, null, 2)}
                </pre>
              </div>
            ))}
          </div>
        </div>
      );
    };

    // Base error content
    const errorContent = (
      <div
        ref={ref}
        role="alert"
        aria-live="polite"
        className={cn(
          'rounded-lg border flex',
          colorStyles.bg,
          colorStyles.border,
          colorStyles.text,
          sizeStyles.padding,
          sizeStyles.gap,
          className,
        )}
        {...props}
      >
        <div className="flex-shrink-0">{iconConfig}</div>
        <div className="flex-1 min-w-0">
          <div className={cn('font-semibold mb-1', sizeStyles.title)}>
            {title}
          </div>
          <div className={cn('opacity-90', sizeStyles.text)}>{userMessage}</div>
          {renderDetails()}
          {(onRetry ||
            actions.length > 0 ||
            isServerError ||
            (showDetails &&
              (normalizedError.code ||
                normalizedError.details ||
                normalizedError.stack ||
                context))) && (
            <div className="mt-4 flex flex-wrap gap-2 items-center">
              {onRetry && (
                <Button
                  variant="outline"
                  size={size === 'sm' ? 'sm' : 'default'}
                  onClick={handleRetry}
                  disabled={isRetrying}
                  className="border-current text-current hover:bg-current/10"
                >
                  {isRetrying ? 'Retrying...' : 'Retry'}
                </Button>
              )}
              {isServerError && apiError.request_id && (
                <>
                  <Button
                    variant="outline"
                    size={size === 'sm' ? 'sm' : 'default'}
                    onClick={handleCopyRequestId}
                    className="border-current text-current hover:bg-current/10"
                    title="Copy Request ID to clipboard"
                  >
                    <Copy className="w-4 h-4 mr-1.5" />
                    Copy Request ID
                  </Button>
                  <Button
                    variant="outline"
                    size={size === 'sm' ? 'sm' : 'default'}
                    onClick={handleReportIssue}
                    className="border-current text-current hover:bg-current/10"
                  >
                    <Bug className="w-4 h-4 mr-1.5" />
                    Report Issue
                  </Button>
                </>
              )}
              {actions.map((action, idx) => (
                <Button
                  key={idx}
                  variant={action.variant || 'outline'}
                  size={size === 'sm' ? 'sm' : 'default'}
                  onClick={action.onClick}
                  className="border-current text-current hover:bg-current/10"
                >
                  {action.label}
                </Button>
              ))}
              {showDetails &&
                (normalizedError.code ||
                  normalizedError.details ||
                  normalizedError.stack ||
                  context) && (
                  <Button
                    variant="ghost"
                    size={size === 'sm' ? 'sm' : 'default'}
                    onClick={() => setIsDetailsExpanded(!isDetailsExpanded)}
                    className="text-current hover:bg-current/10"
                  >
                    {isDetailsExpanded ? (
                      <>
                        <ChevronUp className="w-4 h-4 mr-1" />
                        Hide Details
                      </>
                    ) : (
                      <>
                        <ChevronDown className="w-4 h-4 mr-1" />
                        Show Details
                      </>
                    )}
                  </Button>
                )}
            </div>
          )}
        </div>
        {isDismissible && (
          <button
            onClick={handleDismiss}
            className="opacity-70 hover:opacity-100 transition-opacity flex-shrink-0"
            aria-label="Dismiss error"
          >
            <X className={cn(size === 'sm' ? 'w-4 h-4' : 'w-5 h-5')} />
          </button>
        )}
      </div>
    );

    // Render based on variant
    switch (variant) {
      case 'banner':
        return <div className="w-full">{errorContent}</div>;

      case 'card':
        return (
          <Card className={cn(colorStyles.border, className)}>
            <CardContent className={cn(sizeStyles.padding, 'pt-6')}>
              {errorContent}
            </CardContent>
          </Card>
        );

      case 'modal':
        return (
          <Dialog
            open={isModalOpen}
            onClose={handleDismiss}
            title={title}
            variant={
              severity === 'error'
                ? 'alert'
                : severity === 'warning'
                  ? 'alert'
                  : 'info'
            }
            footer={
              <div className="flex gap-2 justify-end">
                {onRetry && (
                  <Button
                    variant="outline"
                    onClick={handleRetry}
                    disabled={isRetrying}
                  >
                    {isRetrying ? 'Retrying...' : 'Retry'}
                  </Button>
                )}
                {isServerError && apiError.request_id && (
                  <>
                    <Button
                      variant="outline"
                      onClick={handleCopyRequestId}
                      title="Copy Request ID to clipboard"
                    >
                      <Copy className="w-4 h-4 mr-1.5" />
                      Copy Request ID
                    </Button>
                    <Button variant="outline" onClick={handleReportIssue}>
                      <Bug className="w-4 h-4 mr-1.5" />
                      Report Issue
                    </Button>
                  </>
                )}
                {actions.map((action, idx) => (
                  <Button
                    key={idx}
                    variant={action.variant || 'outline'}
                    onClick={action.onClick}
                  >
                    {action.label}
                  </Button>
                ))}
                <Button variant="default" onClick={handleDismiss}>
                  {onRetry ? 'Close' : 'Dismiss'}
                </Button>
              </div>
            }
          >
            <div className={cn(colorStyles.text)}>
              <div className={cn('opacity-90 mb-4', sizeStyles.text)}>
                {userMessage}
                {isServerError && apiError.request_id && (
                  <div className="mt-2 text-xs opacity-75">
                    Request ID:{' '}
                    <code className="bg-black/20 px-1.5 py-0.5 rounded">
                      {apiError.request_id}
                    </code>
                  </div>
                )}
              </div>
              {renderDetails()}
            </div>
          </Dialog>
        );

      case 'inline':
      default:
        return errorContent;
    }
  },
);

ErrorDisplay.displayName = 'ErrorDisplay';
