'use client';

import * as React from 'react';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { useTheme } from '@mui/material/styles';
import { BeatLoader, PropagateLoader } from 'react-spinners';

export type AppLoaderSize = 'xs' | 'sm' | 'md' | 'lg' | 'screen';
export type AppLoaderViewport = 'full' | 'content';

const SIZE_MAP: Record<AppLoaderSize, number> = {
  xs: 8,
  sm: 10,
  md: 14,
  lg: 18,
  screen: 22,
};

const INLINE_SIZE_MAP: Record<AppLoaderSize, number> = {
  xs: 5,
  sm: 6,
  md: 7,
  lg: 8,
  screen: 9,
};

const INLINE_WIDTH_MAP: Record<AppLoaderSize, number> = {
  xs: 24,
  sm: 28,
  md: 32,
  lg: 36,
  screen: 40,
};

const MIN_HEIGHT_MAP: Partial<Record<AppLoaderSize, string | number>> = {
  sm: 120,
  md: 200,
  lg: 400,
};

export interface AppLoaderProps {
  size?: AppLoaderSize;
  color?: string;
  centered?: boolean;
  minHeight?: string | number;
  loading?: boolean;
  label?: string;
  inline?: boolean;
  viewport?: AppLoaderViewport | false;
  fill?: boolean;
  backdrop?: boolean;
  compact?: boolean;
}

export function AppLoader({
  size = 'md',
  color,
  centered = true,
  minHeight,
  loading = true,
  label,
  inline = false,
  viewport,
  fill = false,
  backdrop = true,
  compact = false,
}: AppLoaderProps): React.JSX.Element | null {
  const theme = useTheme();

  if (!loading) {
    return null;
  }

  const loaderColor = color ?? theme.palette.primary.main;
  const propagateSize = SIZE_MAP[size];
  const resolvedViewport = viewport ?? (size === 'screen' ? 'full' : false);

  if (inline || !centered) {
    return (
      <Box
        component="span"
        sx={{
          display: 'inline-flex',
          alignItems: 'center',
          justifyContent: 'center',
          width: INLINE_WIDTH_MAP[size],
          height: 16,
          overflow: 'hidden',
          lineHeight: 0,
          verticalAlign: 'middle',
          flexShrink: 0,
        }}
        role="status"
        aria-busy
        aria-label={label ?? 'Loading'}
      >
        <BeatLoader color={loaderColor} loading={loading} size={INLINE_SIZE_MAP[size]} speedMultiplier={0.9} />
      </Box>
    );
  }

  const spinner = (
    <Box
      sx={{
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        lineHeight: 0,
      }}
    >
      <PropagateLoader color={loaderColor} loading={loading} size={propagateSize} speedMultiplier={0.9} />
    </Box>
  );

  const content = (
    <>
      {spinner}
      {label && !compact && (
        <Typography variant="body2" color="text.secondary" sx={{ mt: 1.5, textAlign: 'center' }}>
          {label}
        </Typography>
      )}
    </>
  );

  if (compact && !fill && !resolvedViewport) {
    return (
      <Box
        sx={{
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',
          justifyContent: 'center',
        }}
        role="status"
        aria-busy
        aria-label={label ?? 'Loading'}
      >
        {content}
      </Box>
    );
  }

  const resolvedMinHeight = minHeight ?? MIN_HEIGHT_MAP[size] ?? 200;

  const layoutStyles =
    resolvedViewport === 'full'
      ? {
          position: 'fixed' as const,
          inset: 0,
          width: '100vw',
          height: '100dvh',
          zIndex: theme.zIndex.modal - 1,
          bgcolor: 'background.default',
        }
      : resolvedViewport === 'content'
        ? {
            position: 'fixed' as const,
            top: 'var(--MainNav-height, 56px)',
            left: { xs: 0, lg: 'var(--SideNav-width, 280px)' },
            right: 0,
            bottom: 0,
            zIndex: theme.zIndex.modal - 1,
            bgcolor: 'background.default',
          }
        : fill
          ? {
              position: 'absolute' as const,
              inset: 0,
              width: '100%',
              height: '100%',
              zIndex: 2,
              ...(backdrop && {
                bgcolor:
                  theme.palette.mode === 'dark' ? 'rgba(26, 32, 44, 0.8)' : 'rgba(255, 255, 255, 0.8)',
                backdropFilter: 'blur(4px)',
              }),
            }
          : {
              width: '100%',
              minHeight: resolvedMinHeight,
            };

  return (
    <Box
      sx={{
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'center',
        ...layoutStyles,
      }}
      role="status"
      aria-busy
      aria-label={label ?? 'Loading'}
    >
      {content}
    </Box>
  );
}
