import styled from '@emotion/styled';
import { useCallback, useEffect, useRef } from 'react';

import { getCountString } from '../../utils/utils';
import Button, {
  Props as ButtonProps,
  ButtonShape,
  ButtonSize,
} from './Button';

const CountFader = styled.span`
  overflow: visible;
  white-space: nowrap;
  opacity: 1;
  transition:
    opacity 0.25s ease-in-out,
    width 0.25s ease-out;
  &.faded {
    opacity: 0;
  }
`;

export type CountButtonProps = ButtonProps & {
  count: number;
  icon: React.ReactNode;
  itemId: string;
  neverShowZeroCount?: boolean;
};

const CountButton = ({
  count,
  icon,
  itemId,
  neverShowZeroCount = false,
  shape = ButtonShape.Pill,
  size = ButtonSize.Mini,
  className,
  ...props
}: CountButtonProps) => {
  const countRef = useRef<HTMLSpanElement>(null);
  const lastItemIdRef = useRef<string | undefined>(undefined);
  const displayUpdateTimeoutRef = useRef<
    ReturnType<typeof setTimeout> | undefined
  >(undefined);

  const setCount = useCallback((count: number) => {
    if (!countRef.current) {
      return;
    }
    countRef.current.textContent = getCountString(count);
  }, []);

  const updateCount = useCallback(
    (itemId: string, count: number) => {
      if (!countRef.current) {
        return;
      }
      if (displayUpdateTimeoutRef.current) {
        clearTimeout(displayUpdateTimeoutRef.current);
        countRef.current.classList.remove('faded');
      }
      if (lastItemIdRef.current !== itemId) {
        setCount(count);
        lastItemIdRef.current = itemId;
      } else {
        countRef.current.classList.add('faded');
        displayUpdateTimeoutRef.current = setTimeout(() => {
          if (!countRef.current) return;
          setCount(count);
          countRef.current.classList.remove('faded');
        }, 250);
      }
    },
    [setCount]
  );

  useEffect(() => {
    updateCount(itemId, count);
  }, [itemId, count, updateCount]);

  return (
    <Button {...props} shape={shape} size={size} className={className}>
      {icon}
      {!(neverShowZeroCount && count === 0) && (
        <CountFader ref={countRef} className='px-0.5' />
      )}
    </Button>
  );
};

export default CountButton;
