import * as React from 'react';
import { AlertTriangle, AlertCircle, Info, X, ChevronDown, ChevronUp } 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 '@/types/api';
import { formatUserFriendlyError } from '@/utils/errorMessages';
import { parseApiError } from '@/utils/apiErrorHandler';

/**
 * 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]);

    // 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]);

    // 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 }> = [];

      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 || (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>
              )}
              {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>
                )}
                {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}
              </div>
              {renderDetails()}
            </div>
          </Dialog>
        );

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

ErrorDisplay.displayName = 'ErrorDisplay';
