import React, { ReactNode, useContext, useState } from "react";
import classNames from "classnames";
import { Box, BoxProps } from "../Box";
import { bem } from "../../utilities/bem";
import { CardGroupContext } from "./CardGroupContext";
import { CardGroup } from "./CardGroup";

const cn = "Card";

export interface BodyProps {
  as?: any;
  [key: string]: any;
}

export interface CardProps extends BoxProps {
  /**
   * Value in pixels to be used for the height and width of the entire card (including footer if provided).
   * NOTE: If rendering more than one card, use the `Card.Group` component for sizing instead of this prop
   */
  cardSize?: number;
  /**
   * Content to render in the main body of the card
   */
  bodySlot: ReactNode;
  /**
   * Props object to apply to the `bodySlot` container element.  By default, the `bodySlot` container renders as a `<button>`.  Pass an `as` prop to render it as another element or component
   */
  bodyProps?: any;
  /**
   * Content to render in the footer of the card
   */
  footerSlot?: ReactNode;
  /**
   * Gives the card body a hover state
   */
  clickable?: boolean;
  /**
   * CSS color to use for the top border of the card
   */
  accentColor?: string;
  /**
   * Where to place the accentColor
   */
  accentColorPlacement?: "top" | "left";
  /**
   * Disables click events in the body and footer of the card
   */
  cardDisabled?: boolean;
  /**
   * Disables click events in the body of the card
   */
  bodyDisabled?: boolean;
  /**
   * Gives card faded appearance
   */
  isPlaceholder?: boolean;
}

export const Card = ({
  cardSize,
  bodySlot,
  bodyProps,
  footerSlot,
  clickable = false,
  accentColor,
  accentColorPlacement = "top",
  cardDisabled = false,
  bodyDisabled = false,
  className,
  isPlaceholder = false,
  ...rest
}: CardProps) => {
  const defaultBodyProps = { as: clickable ? "button" : "div" };
  const combinedBodyProps = { ...defaultBodyProps, ...bodyProps };
  const {
    as: Component,
    className: bodyClassName,
    ...bodyRest
  } = combinedBodyProps;
  const { hasAccents: contextHasAccents } = useContext(CardGroupContext);
  const hasAccent = accentColor || contextHasAccents;
  const [isHovered, setIsHovered] = useState(false);

  return (
    <Box
      style={{
        height: cardSize,
        width: cardSize,
        borderColor: hasAccent ? accentColor || "transparent" : "",
      }}
      className={classNames(
        bem(cn),
        isPlaceholder && bem(cn, { m: "isPlaceholder" }),
        hasAccent && bem(cn, { m: `hasAccent-${accentColorPlacement}` }),
        className,
      )}
      {...rest}
    >
      {clickable && (
        <Box
          className={classNames(
            bem(cn, { e: "hoverOverlay" }),
            isHovered && bem(cn, { e: "hoverOverlay", m: "hovered" }),
          )}
        />
      )}
      {(cardDisabled || bodyDisabled) && (
        <Box
          className={classNames(bem(cn, { e: "cardDisabledOverlay" }))}
          onClick={(e) => e.stopPropagation()}
        />
      )}
      <Component
        className={classNames("group", bem(cn, { e: "body" }), bodyClassName)}
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
        {...bodyRest}
      >
        {bodySlot}
      </Component>
      {footerSlot && (
        <Box
          className={classNames(
            bem(cn, { e: "footer" }),
            bodyDisabled && bem(cn, { e: "footer", m: "enabled" }),
          )}
        >
          {footerSlot}
        </Box>
      )}
    </Box>
  );
};

Card.Group = CardGroup;
