import React from "react";
import {
  Box,
  IconButton,
  Skeleton,
  useColorModeValue,
  useTheme,
  useToken,
} from "@chakra-ui/react";
import { ClassNames } from "@emotion/react";

import { safeImageUrl, useCommonStyles } from "../util";
import { CheckIcon, CloseIcon, StarIcon } from "@chakra-ui/icons";
import usePreferArchive from "./usePreferArchive";

function SquareItemCard({
  item,
  showRemoveButton = false,
  onRemove = () => {},
  tradeMatchingMode = null,
  footer = null,
  ...props
}) {
  const outlineShadowValue = useToken("shadows", "outline");
  const mdRadiusValue = useToken("radii", "md");

  const tradeMatchOwnShadowColor = useColorModeValue("green.500", "green.200");
  const tradeMatchWantShadowColor = useColorModeValue("blue.400", "blue.200");
  const [tradeMatchOwnShadowColorValue, tradeMatchWantShadowColorValue] =
    useToken("colors", [tradeMatchOwnShadowColor, tradeMatchWantShadowColor]);

  // When this is a trade match, give it an extra colorful shadow highlight so
  // it stands out! (They'll generally be sorted to the front anyway, but this
  // make it easier to scan a user's lists page, and to learn how the sorting
  // works!)
  let tradeMatchShadow;
  if (tradeMatchingMode === "offering" && item.currentUserWantsThis) {
    tradeMatchShadow = `0 0 6px ${tradeMatchWantShadowColorValue}`;
  } else if (tradeMatchingMode === "seeking" && item.currentUserOwnsThis) {
    tradeMatchShadow = `0 0 6px ${tradeMatchOwnShadowColorValue}`;
  } else {
    tradeMatchShadow = null;
  }

  return (
    <ClassNames>
      {({ css }) => (
        // SquareItemCard renders in large lists of 1k+ items, so we get a big
        // perf win by using Emotion directly instead of Chakra's styled-system
        // Box.
        <div
          className={css`
            position: relative;
            display: flex;
          `}
          role="group"
        >
          <Box
            as="a"
            href={`/items/${item.id}`}
            className={css`
              border-radius: ${mdRadiusValue};
              transition: all 0.2s;
              &:hover,
              &:focus {
                transform: scale(1.05);
              }
              &:focus {
                box-shadow: ${outlineShadowValue};
                outline: none;
              }
            `}
            {...props}
          >
            <SquareItemCardLayout
              name={item.name}
              thumbnailImage={
                <ItemThumbnail
                  item={item}
                  tradeMatchingMode={tradeMatchingMode}
                />
              }
              removeButton={
                showRemoveButton ? (
                  <SquareItemCardRemoveButton onClick={onRemove} />
                ) : null
              }
              boxShadow={tradeMatchShadow}
              footer={footer}
            />
          </Box>
          {showRemoveButton && (
            <div
              className={css`
                position: absolute;
                right: 0;
                top: 0;
                transform: translate(50%, -50%);
                z-index: 1;

                /* Apply some padding, so accidental clicks around the button
                 * don't click the link instead, or vice-versa! */
                padding: 0.75em;

                opacity: 0;
                [role="group"]:hover &,
                [role="group"]:focus-within &,
                &:hover,
                &:focus-within {
                  opacity: 1;
                }
              `}
            >
              <SquareItemCardRemoveButton onClick={onRemove} />
            </div>
          )}
        </div>
      )}
    </ClassNames>
  );
}

function SquareItemCardLayout({
  name,
  thumbnailImage,
  footer,
  minHeightNumLines = 2,
  boxShadow = null,
}) {
  const { brightBackground } = useCommonStyles();
  const brightBackgroundValue = useToken("colors", brightBackground);
  const theme = useTheme();

  return (
    // SquareItemCard renders in large lists of 1k+ items, so we get a big perf
    // win by using Emotion directly instead of Chakra's styled-system Box.
    <ClassNames>
      {({ css }) => (
        <div
          className={css`
            display: flex;
            flex-direction: column;
            align-items: center;
            text-align: center;
            box-shadow: ${boxShadow || theme.shadows.md};
            border-radius: ${theme.radii.md};
            padding: ${theme.space["3"]};
            width: calc(80px + 2em);
            background: ${brightBackgroundValue};
          `}
        >
          {thumbnailImage}
          <div
            className={css`
              margin-top: ${theme.space["1"]};
              font-size: ${theme.fontSizes.sm};
              /* Set min height to match a 2-line item name, so the cards
               * in a row aren't toooo differently sized... */
              min-height: ${minHeightNumLines * 1.5 + "em"};
              -webkit-line-clamp: 3;
              -webkit-box-orient: vertical;
              overflow: hidden;
              text-overflow: ellipsis;
              width: 100%;
            `}
            // HACK: Emotion turns this into -webkit-display: -webkit-box?
            style={{ display: "-webkit-box" }}
          >
            {name}
          </div>
          {footer && (
            <Box marginTop="2" width="100%">
              {footer}
            </Box>
          )}
        </div>
      )}
    </ClassNames>
  );
}

function ItemThumbnail({ item, tradeMatchingMode }) {
  const [preferArchive] = usePreferArchive();
  const kindColorScheme = item.isNc ? "purple" : item.isPb ? "orange" : "gray";

  const thumbnailShadowColor = useColorModeValue(
    `${kindColorScheme}.200`,
    `${kindColorScheme}.600`,
  );
  const thumbnailShadowColorValue = useToken("colors", thumbnailShadowColor);
  const mdRadiusValue = useToken("radii", "md");

  // Normally, we just show the owns/wants badges depending on whether the
  // current user owns/wants it. But, in a trade list, we use trade-matching
  // mode instead: only show the badge if it represents a viable trade, and add
  // some extra flair to it, too!
  let showOwnsBadge;
  let showWantsBadge;
  let showTradeMatchFlair;
  if (tradeMatchingMode == null) {
    showOwnsBadge = item.currentUserOwnsThis;
    showWantsBadge = item.currentUserWantsThis;
    showTradeMatchFlair = false;
  } else if (tradeMatchingMode === "offering") {
    showOwnsBadge = false;
    showWantsBadge = item.currentUserWantsThis;
    showTradeMatchFlair = true;
  } else if (tradeMatchingMode === "seeking") {
    showOwnsBadge = item.currentUserOwnsThis;
    showWantsBadge = false;
    showTradeMatchFlair = true;
  } else if (tradeMatchingMode === "hide-all") {
    showOwnsBadge = false;
    showWantsBadge = false;
    showTradeMatchFlair = false;
  } else {
    throw new Error(`unexpected tradeMatchingMode ${tradeMatchingMode}`);
  }

  return (
    <ClassNames>
      {({ css }) => (
        <div
          className={css`
            position: relative;
          `}
        >
          <img
            src={safeImageUrl(item.thumbnailUrl, { preferArchive })}
            alt={`Thumbnail art for ${item.name}`}
            width={80}
            height={80}
            className={css`
              border-radius: ${mdRadiusValue};
              box-shadow: 0 0 4px ${thumbnailShadowColorValue};

              /* Don't let alt text flash in while loading */
              &:-moz-loading {
                visibility: hidden;
              }
            `}
            loading="lazy"
          />
          <div
            className={css`
              position: absolute;
              top: -6px;
              left: -6px;
              display: flex;
              flex-direction: column;
              gap: 2px;
            `}
          >
            {showOwnsBadge && (
              <ItemOwnsWantsBadge
                colorScheme="green"
                label={
                  showTradeMatchFlair
                    ? "You own this, and they want it!"
                    : "You own this"
                }
              >
                <CheckIcon />
                {showTradeMatchFlair && (
                  <div
                    className={css`
                      margin-left: 0.25em;
                      margin-right: 0.125rem;
                    `}
                  >
                    Match
                  </div>
                )}
              </ItemOwnsWantsBadge>
            )}
            {showWantsBadge && (
              <ItemOwnsWantsBadge
                colorScheme="blue"
                label={
                  showTradeMatchFlair
                    ? "You want this, and they own it!"
                    : "You want this"
                }
              >
                <StarIcon />
                {showTradeMatchFlair && (
                  <div
                    className={css`
                      margin-left: 0.25em;
                      margin-right: 0.125rem;
                    `}
                  >
                    Match
                  </div>
                )}
              </ItemOwnsWantsBadge>
            )}
          </div>
          {item.isNc != null && (
            <div
              className={css`
                position: absolute;
                bottom: -6px;
                right: -3px;
              `}
            >
              <ItemThumbnailKindBadge colorScheme={kindColorScheme}>
                {item.isNc ? "NC" : item.isPb ? "PB" : "NP"}
              </ItemThumbnailKindBadge>
            </div>
          )}
        </div>
      )}
    </ClassNames>
  );
}

function ItemOwnsWantsBadge({ colorScheme, children, label }) {
  const badgeBackground = useColorModeValue(
    `${colorScheme}.100`,
    `${colorScheme}.500`,
  );
  const badgeColor = useColorModeValue(
    `${colorScheme}.500`,
    `${colorScheme}.100`,
  );

  const [badgeBackgroundValue, badgeColorValue] = useToken("colors", [
    badgeBackground,
    badgeColor,
  ]);

  return (
    <ClassNames>
      {({ css }) => (
        <div
          aria-label={label}
          title={label}
          className={css`
            border-radius: 999px;
            height: 16px;
            min-width: 16px;
            font-size: 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 0 2px ${badgeBackgroundValue};
            /* Decrease the padding: I don't want to hit the edges, but I want
             * to be a circle when possible! */
            padding-left: 0.125rem;
            padding-right: 0.125rem;
            /* Copied from Chakra <Badge> */
            white-space: nowrap;
            vertical-align: middle;
            text-transform: uppercase;
            font-size: 0.65rem;
            font-weight: 700;
            background: ${badgeBackgroundValue};
            color: ${badgeColorValue};
          `}
        >
          {children}
        </div>
      )}
    </ClassNames>
  );
}

function ItemThumbnailKindBadge({ colorScheme, children }) {
  const badgeBackground = useColorModeValue(
    `${colorScheme}.100`,
    `${colorScheme}.500`,
  );
  const badgeColor = useColorModeValue(
    `${colorScheme}.500`,
    `${colorScheme}.100`,
  );

  const [badgeBackgroundValue, badgeColorValue] = useToken("colors", [
    badgeBackground,
    badgeColor,
  ]);

  return (
    <ClassNames>
      {({ css }) => (
        <div
          className={css`
            /* Copied from Chakra <Badge> */
            white-space: nowrap;
            vertical-align: middle;
            padding-left: 0.25rem;
            padding-right: 0.25rem;
            text-transform: uppercase;
            font-size: 0.65rem;
            border-radius: 0.125rem;
            font-weight: 700;
            background: ${badgeBackgroundValue};
            color: ${badgeColorValue};
          `}
        >
          {children}
        </div>
      )}
    </ClassNames>
  );
}

function SquareItemCardRemoveButton({ onClick }) {
  const backgroundColor = useColorModeValue("gray.200", "gray.500");

  return (
    <IconButton
      aria-label="Remove"
      title="Remove"
      icon={<CloseIcon />}
      size="xs"
      borderRadius="full"
      boxShadow="lg"
      backgroundColor={backgroundColor}
      onClick={onClick}
      _hover={{
        // Override night mode's fade-out on hover
        opacity: 1,
        transform: "scale(1.15, 1.15)",
      }}
      _focus={{
        transform: "scale(1.15, 1.15)",
        boxShadow: "outline",
      }}
    />
  );
}

export function SquareItemCardSkeleton({ minHeightNumLines, footer = null }) {
  return (
    <SquareItemCardLayout
      name={
        <>
          <Skeleton width="100%" height="1em" marginTop="2" />
          {minHeightNumLines >= 3 && (
            <Skeleton width="100%" height="1em" marginTop="2" />
          )}
        </>
      }
      thumbnailImage={<Skeleton width="80px" height="80px" />}
      minHeightNumLines={minHeightNumLines}
      footer={footer}
    />
  );
}

export default SquareItemCard;