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

import CardContext from './CardContext';
import CardContent from './CardContent';
import CardHeader from './CardHeader';
import { StyledCard, StyledCardImg } from './StyledCard';

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

export interface CardProps extends CommonProps {
  /**
   * Display border.
   */
  border?: boolean;
  /**
   * Custom content.
   */
  children?: ReactNode;
  /**
   * Short hand for Card content.
   */
  content?: string | ReactElement;
  /**
   * Short hand for Card content with format as extra content.
   */
  extra?: string | ReactElement;
  /**
   * Short hand for Card header.
   */
  header?: string | ReactElement;
  /**
   * Card image.
   */
  imageSrc?: string;
  /**
   * Card size. This will affect the padding of card's header and content.
   */
  size?: 'small' | 'medium';
  /**
   * Card variant.
   */
  variant?: 'basic' | 'primary' | 'info' | 'grey';
}

const Card = ({
  header,
  content,
  extra,
  variant = 'basic',
  size = 'medium',
  imageSrc,
  border = true,
  children,
  id,
  className,
  style,
  sx = {},
  'data-test-id': dataTestId,
}: CardProps): ReactElement => {
  const cardVariant = border === true ? 'withBorder' : 'withoutBorder';

  const wrapWithStyledCard = (cardInner: ReactNode): ReactElement => (
    <CardContext.Provider value={{ variant, size }}>
      <StyledCard
        themeStatus={cardVariant}
        id={id}
        className={className}
        style={{ ...style, ...css(sx) }}
        data-test-id={dataTestId}
      >
        {cardInner}
      </StyledCard>
    </CardContext.Provider>
  );

  return pipe(
    children,
    fromUndefinedable,
    map(wrapWithStyledCard),
    getOrElse(() =>
      wrapWithStyledCard(
        <>
          {imageSrc !== undefined && (
            <StyledCardImg src={imageSrc} alt="card-img" />
          )}
          {header !== undefined && <CardHeader content={header} />}
          {content !== undefined && <CardContent content={content} />}
          {extra !== undefined && <CardContent content={extra} extra />}
        </>
      )
    )
  );
};

Card.Header = CardHeader;
Card.Content = CardContent;

export default Card;
