import {
  Button,
  type ButtonProps,
  CircularProgress,
  type CircularProgressProps,
  SxProps,
  Theme,
  Typography,
} from '@mui/material';

export interface LoadingButtonProps extends ButtonProps {
  loading?: boolean;
  loadingIndicator?: React.ReactNode;
  loadingPosition?: 'start' | 'center' | 'end';
  loadingProps?: Partial<CircularProgressProps>;
  loadingOnly?: boolean;
}

export default function LoadingButton({
  ref = undefined,
  children,
  loading = false,
  loadingPosition = 'start',
  loadingIndicator = undefined,
  loadingProps = {},
  loadingOnly = false,
  onClick,
  sx,
  ...props
}: LoadingButtonProps & {
  ref?: React.RefObject<HTMLButtonElement | null>;
}) {
  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    if (loading) {
      return;
    }
    onClick?.(e);
  };

  const getPositionStyles = (position: string) => {
    return {
      color: 'inherit',
      ...(position === 'start' && { mr: 1 }),
      ...(position === 'end' && { ml: 1 }),
      ...(position === 'center' && {
        position: 'absolute',
        left: '50%',
        transform: 'translateY(-50%) translateX(-50%)',
        top: '50%',
      }),
      display: 'inline-flex',
      alignItems: 'center',
    } as const;
  };

  const defaultIndicator = (
    <CircularProgress size={16} {...loadingProps} sx={{ color: 'inherit', ...(loadingProps?.sx || {}) }} />
  );

  const indicator = (
    <Typography sx={getPositionStyles(loadingPosition) as SxProps<Theme>}>
      {loadingIndicator || defaultIndicator}
    </Typography>
  );

  return (
    <Button
      ref={ref}
      disabled={props.disabled || loading}
      onClick={handleClick}
      sx={{
        position: 'relative',
        display: 'inline-flex',
        alignItems: 'center',
        justifyContent: 'center',
        ...sx,
      }}
      {...props}>
      {loading && loadingPosition === 'start' && indicator}
      <Typography sx={{ visibility: loading && loadingOnly ? 'hidden' : 'visible' }}>{children}</Typography>
      {loading && loadingPosition === 'center' && indicator}
      {loading && loadingPosition === 'end' && indicator}
    </Button>
  );
}

LoadingButton.displayName = 'LoadingButton';
