import React, { ReactElement, ReactNode } from 'react';
import css from '../../utils/css';

import { CommonProps } from '../common';
import {
  SpinnerContainer,
  SpinnerWrapper,
  StyledSpinner,
  ContentWrapper,
} from './StyledSpinner';
import { fromUndefinedable, getOrElse, map } from '../../fp/Option';
import { pipe } from '../../fp/function';

export interface SpinnerProps extends CommonProps {
  /**
   * Content expected to be loaded.
   */
  children?: ReactNode;
  /**
   * Loading state of content wrapped by spinner. This is required when children is present.
   */
  loading?: boolean;
  /**
   * Size of spinner
   */
  size?: 'small' | 'medium' | 'large';
  /**
   * Additional text
   */
  text?: string;
}

const Spinner = ({
  text,
  size = 'medium',
  loading = false,
  children,
  id,
  className,
  style,
  sx = {},
  'data-test-id': dataTestId,
}: SpinnerProps): ReactElement => {
  const spinningElement = (
    <SpinnerWrapper
      themeSize={size}
      id={id}
      className={className}
      style={{ ...style, ...css(sx) }}
      data-test-id={dataTestId}
    >
      <StyledSpinner themeSize={size} />
      {text}
    </SpinnerWrapper>
  );

  const maybeChildren = fromUndefinedable(children);

  return pipe(
    maybeChildren,
    map(c => (
      <SpinnerContainer themeSize={size}>
        <ContentWrapper themeLoading={loading}>{c}</ContentWrapper>
        {loading === true && spinningElement}
      </SpinnerContainer>
    )),
    getOrElse(() => spinningElement)
  );
};

export default Spinner;
