import React from 'react';
import { 
  Stack, 
  Text, 
  Loader, 
  Center, 
  Progress, 
  Box, 
  Group,
  Skeleton,
  Card,
  SimpleGrid,
} from '@mantine/core';

export type LoadingVariant = 
  | 'spinner'           // Simple spinner with text
  | 'progress'          // Progress bar with percentage
  | 'skeleton-table'    // Table skeleton
  | 'skeleton-cards'    // Card grid skeleton
  | 'skeleton-form'     // Form skeleton
  | 'skeleton-text'     // Text content skeleton
  | 'dots'              // Animated dots
  | 'overlay';          // Full overlay spinner

export type LoadingSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';

export interface LoadingStateProps {
  variant?: LoadingVariant;
  size?: LoadingSize;
  height?: number | string;
  
  // Text content
  message?: string;
  submessage?: string;
  
  // Progress specific
  progress?: number; // 0-100
  progressLabel?: string;
  
  // Skeleton specific
  rows?: number;
  columns?: number;
  
  // Styling
  color?: string;
  withContainer?: boolean;
  
  // Animation
  animate?: boolean;
}

const LoadingState: React.FC<LoadingStateProps> = ({
  variant = 'spinner',
  size = 'md',
  height = 200,
  message,
  submessage,
  progress,
  progressLabel,
  rows = 5,
  columns = 3,
  color = 'blue',
  withContainer = true,
  animate = true,
}) => {
  const getLoaderSize = (): number => {
    const sizeMap: Record<LoadingSize, number> = {
      xs: 16,
      sm: 24,
      md: 32,
      lg: 48,
      xl: 64,
    };
    return sizeMap[size];
  };

  const getTextSize = (): string => {
    const sizeMap: Record<LoadingSize, string> = {
      xs: 'xs',
      sm: 'sm',
      md: 'md',
      lg: 'lg',
      xl: 'xl',
    };
    return sizeMap[size];
  };

  const renderSpinner = () => (
    <Stack align="center" gap="md">
      <Loader size={getLoaderSize()} color={color} />
      {message && (
        <Text size={getTextSize()} c="dimmed" ta="center">
          {message}
        </Text>
      )}
      {submessage && (
        <Text size="xs" c="dimmed" ta="center">
          {submessage}
        </Text>
      )}
    </Stack>
  );

  const renderProgress = () => (
    <Stack gap="md">
      {(message || progressLabel) && (
        <Group justify="space-between">
          <Text size={getTextSize()}>
            {message || 'Loading...'}
          </Text>
          {progressLabel && (
            <Text size="sm" c="dimmed">
              {progressLabel}
            </Text>
          )}
        </Group>
      )}
      
      <Progress 
        value={progress || 0} 
        color={color}
        size={size}
        animated={animate}
      />
      
      {submessage && (
        <Text size="xs" c="dimmed" ta="center">
          {submessage}
        </Text>
      )}
    </Stack>
  );

  const renderSkeletonTable = () => (
    <Stack gap="xs">
      {/* Table header */}
      <Group gap="md">
        {Array.from({ length: columns }).map((_, i) => (
          <Skeleton key={`header-${i}`} height={20} width={`${100 / columns}%`} />
        ))}
      </Group>
      
      {/* Table rows */}
      {Array.from({ length: rows }).map((_, rowIndex) => (
        <Group key={`row-${rowIndex}`} gap="md">
          {Array.from({ length: columns }).map((_, colIndex) => (
            <Skeleton 
              key={`cell-${rowIndex}-${colIndex}`} 
              height={16} 
              width={`${100 / columns}%`}
            />
          ))}
        </Group>
      ))}
    </Stack>
  );

  const renderSkeletonCards = () => (
    <SimpleGrid cols={{ base: 1, sm: 2, lg: columns }}>
      {Array.from({ length: rows * columns }).map((_, i) => (
        <Card key={`card-${i}`} padding="md" withBorder>
          <Stack gap="xs">
            <Skeleton height={20} width="70%" />
            <Skeleton height={14} />
            <Skeleton height={14} width="90%" />
            <Group justify="apart" mt="md">
              <Skeleton height={12} width="40%" />
              <Skeleton height={12} width="30%" />
            </Group>
          </Stack>
        </Card>
      ))}
    </SimpleGrid>
  );

  const renderSkeletonForm = () => (
    <Stack gap="md">
      {Array.from({ length: rows }).map((_, i) => (
        <Box key={`form-field-${i}`}>
          <Skeleton height={12} width="30%" mb="xs" />
          <Skeleton height={36} />
        </Box>
      ))}
      
      <Group justify="flex-end" mt="xl">
        <Skeleton height={36} width={80} />
        <Skeleton height={36} width={100} />
      </Group>
    </Stack>
  );

  const renderSkeletonText = () => (
    <Stack gap="xs">
      {Array.from({ length: rows }).map((_, i) => {
        // Vary line widths for more realistic skeleton
        const widths = ['100%', '95%', '85%', '90%', '75%'];
        return (
          <Skeleton 
            key={`text-${i}`} 
            height={16} 
            width={widths[i % widths.length]} 
          />
        );
      })}
    </Stack>
  );

  const renderDots = () => {
    const dots = Array.from({ length: 3 }).map((_, i) => (
      <Box
        key={i}
        w={8}
        h={8}
        bg={color}
        style={{
          borderRadius: '50%',
          animation: animate ? `loading-dots 1.4s infinite ease-in-out ${i * 0.16}s` : undefined,
        }}
      />
    ));

    return (
      <Stack align="center" gap="md">
        <Group gap="xs">
          {dots}
        </Group>
        {message && (
          <Text size={getTextSize()} c="dimmed" ta="center">
            {message}
          </Text>
        )}
      </Stack>
    );
  };

  const renderOverlay = () => (
    <Box
      style={{
        position: 'absolute',
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        backgroundColor: 'rgba(255, 255, 255, 0.8)',
        backdropFilter: 'blur(2px)',
        zIndex: 1000,
      }}
    >
      <Center h="100%">
        {renderSpinner()}
      </Center>
    </Box>
  );

  const getContent = () => {
    switch (variant) {
      case 'progress':
        return renderProgress();
      case 'skeleton-table':
        return renderSkeletonTable();
      case 'skeleton-cards':
        return renderSkeletonCards();
      case 'skeleton-form':
        return renderSkeletonForm();
      case 'skeleton-text':
        return renderSkeletonText();
      case 'dots':
        return renderDots();
      case 'overlay':
        return renderOverlay();
      default:
        return renderSpinner();
    }
  };

  // For overlay variant, don't wrap in container
  if (variant === 'overlay') {
    return (
      <>
        {getContent()}
        <style>{loadingDotsKeyframes}</style>
      </>
    );
  }

  const content = (
    <>
      {getContent()}
      {animate && <style>{loadingDotsKeyframes}</style>}
    </>
  );

  if (!withContainer) {
    return content;
  }

  return (
    <Center h={height}>
      {content}
    </Center>
  );
};

// CSS keyframes for dot animation
const loadingDotsKeyframes = `
  @keyframes loading-dots {
    0%, 80%, 100% {
      transform: scale(0);
      opacity: 0.5;
    }
    40% {
      transform: scale(1);
      opacity: 1;
    }
  }
`;

export default LoadingState;

// Convenience components for common loading scenarios
export const TableLoadingState: React.FC<{ rows?: number; columns?: number }> = 
  ({ rows = 5, columns = 4 }) => (
    <LoadingState variant="skeleton-table" rows={rows} columns={columns} withContainer={false} />
  );

export const CardsLoadingState: React.FC<{ count?: number; columns?: number }> = 
  ({ count = 6, columns = 3 }) => (
    <LoadingState 
      variant="skeleton-cards" 
      rows={Math.ceil(count / columns)} 
      columns={columns} 
      withContainer={false} 
    />
  );

export const FormLoadingState: React.FC<{ fields?: number }> = 
  ({ fields = 4 }) => (
    <LoadingState variant="skeleton-form" rows={fields} withContainer={false} />
  );

export const PageLoadingState: React.FC<{ message?: string }> = 
  ({ message = 'Loading page...' }) => (
    <LoadingState variant="spinner" message={message} height="60vh" size="lg" />
  );

export const InlineLoadingState: React.FC<{ message?: string; size?: LoadingSize }> = 
  ({ message = 'Loading...', size = 'sm' }) => (
    <Group gap="xs">
      <Loader size={size === 'xs' ? 12 : size === 'sm' ? 16 : 20} />
      <Text size={size} c="dimmed">{message}</Text>
    </Group>
  );

// Hook for loading state management
export const useLoadingState = (initialLoading = false) => {
  const [loading, setLoading] = React.useState(initialLoading);
  const [progress, setProgress] = React.useState(0);
  
  const startLoading = React.useCallback(() => setLoading(true), []);
  const stopLoading = React.useCallback(() => {
    setLoading(false);
    setProgress(0);
  }, []);
  
  const updateProgress = React.useCallback((value: number) => {
    setProgress(Math.max(0, Math.min(100, value)));
  }, []);
  
  return {
    loading,
    progress,
    startLoading,
    stopLoading,
    updateProgress,
    setLoading,
    setProgress,
  };
};