import React, {useEffect, useState} from 'react';
import styled from 'styled-components';
import {useDrag} from 'react-dnd';
import {TouchIcon} from '../icons';

const CardElement = styled.div`
  transition: transform 0.35s, z-index 0s 0.35s;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  border-radius: 8px;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 1.25em;
  overflow: hidden;
  user-select: none;
  cursor: pointer;
  @media screen and (min-width: 1100px) {
    font-size: 16px;
  }

  &.is-dragging {
    background: red;
    transition: none;
  }
`;

const TouchIconWrap = styled.div`
  color: #fff;
  width: 50px;
  max-width: 30%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transition: color 0.25s;

  ${CardElement}:hover & {
    color: #2cce9f;
  }
`;

const DraggableCard = ({
  bgColor,
  isBroadcastingDrag = true,
  isFlipBroadcasted,
  color,
  socket,
  text,
  type,
  setUserIsDragging,
  flippedByDefault = false,
  isFlippable = true,
  screen = '',
  isMyCardsOpen,
  isSubmittedTableOpen,
}) => {
  const [ghostCard, setGhostCard] = useState({});
  const [isFlipped, setFlipped] = useState(flippedByDefault);
  const [{isDragging, getDifferenceFromInitialOffset}, drag] = useDrag({
    item: {
      type,
      id: 0,
      text,
      bgColor,
      color,
      isFlipped,
    },
    collect: (monitor) => ({
      isDragging: !!monitor.isDragging() && !Object.keys(ghostCard).length,
      getDifferenceFromInitialOffset:
        !!monitor.isDragging() && monitor.getDifferenceFromInitialOffset(),
    }),
  });

  if (isDragging && getDifferenceFromInitialOffset) {
    const {x, y} = getDifferenceFromInitialOffset;

    if (isBroadcastingDrag) {
      // send dragged card to server
      socket.emit('dragged card', {type, text, x, y});
    }
  }

  useEffect(() => {
    setUserIsDragging(type);

    if (isBroadcastingDrag) {
      if (!isDragging) {
        // send card that was let go to server
        socket.emit('let go card', {ghostDragging: false, type, text});
      }
    }

    if (!isDragging) {
      setUserIsDragging(null);
    }

    return () => {
      setUserIsDragging(null);
    };
  }, [isBroadcastingDrag, setUserIsDragging, socket, text, type, isDragging]);

  useEffect(() => {
    let isMounted = true;
    if (isBroadcastingDrag) {
      // on everyones client but the sender, show the card being returned to deck if let go prematurely
      socket.on('let go card', ({text: otherText}) => {
        if (isMounted && text === otherText) {
          setGhostCard({});
        }
      });

      // on everyones client but the sender, show the card being dragged
      socket.on('dragged card', ({text: otherText, x, y, type}) => {
        if (isMounted && text === otherText) {
          // if i'm looking at my cards, never drag cards on other screens
          if (isMyCardsOpen && !isSubmittedTableOpen) {
            return;
          }
          // if the card that is being dragged is on the submitted cards screen
          // and the submitted cards screen isn't open, then don't set state
          if (screen === 'submittedCards' && !isSubmittedTableOpen) {
            return;
          }
          // if the card that is being dragged is on the main screen
          // and the submitted cards screen is open, then don't set state
          if (screen === 'main' && isSubmittedTableOpen) {
            return;
          }

          setGhostCard({x, y, text});
        }
      });
    }

    if (isFlipBroadcasted) {
      socket.on('card is flipped', function ({isFlipped, text: otherText}) {
        if (isMounted && text === otherText) {
          setFlipped(isFlipped);
        }
      });
    }

    return () => {
      // socket.off('let go card');
      // socket.off('dragged cards');
      isMounted = false;
    };
  }, [
    isBroadcastingDrag,
    setUserIsDragging,
    socket,
    text,
    type,
    isFlipBroadcasted,
    isMyCardsOpen,
    isSubmittedTableOpen,
    screen
  ]);

  const getTransform = () => {
    if (isBroadcastingDrag) {
      // any cards being dragged by someone else
      if (Object.keys(ghostCard).length) {
        if (ghostCard.text === text) {
          return {
            pointerEvents: 'none',
            opacity: '1',
            transform: `translate3d(${ghostCard.x}px, ${ghostCard.y}px, 0)`,
            zIndex: '999',
          };
        } else {
          return {pointerEvents: 'none', transform: 'translate3d(0, 0, 0)'};
        }
      }
    }

    // on the client that's actually dragging the card
    if (isDragging && getDifferenceFromInitialOffset) {
      return {
        pointerEvents: 'none',
        transform: `translate3d(${getDifferenceFromInitialOffset.x}px, ${getDifferenceFromInitialOffset.y}px, 0)`,
      };
    }

    return {transform: 'translate3d(0, 0, 0)'};
  };

  const getClassName = () => {
    if (isBroadcastingDrag) {
      // any cards being dragged by someone else
      if (Object.keys(ghostCard).length) {
        if (ghostCard.text === text) {
          return 'is-dragging';
        } else {
          return null;
        }
      }
    }

    // on the client that's actually dragging the card
    if (isDragging && getDifferenceFromInitialOffset) {
      return 'is-dragging';
    }

    return null;
  };

  return (
    <CardElement
      className={getClassName()}
      onClick={() => {
        if (isFlippable) {
          setFlipped((isFlipped) => {
            socket.emit('card is flipped', {isFlipped: !isFlipped, text});
            return !isFlipped;
          });
        }
      }}
      ref={drag}
      style={{
        zIndex: isDragging ? 999 : '0',
        ...getTransform(),
        backgroundColor: bgColor,
        color,
        justifyContent: isFlipped ? '' : 'flex-start',
      }}
    >
      {isFlipped ? (
        text
      ) : (
        <>
          <div
            className={`LogoInCard ${
              type === 'whiteCard' ? 'LogoInCard--whiteCard' : ''
            }`}
          />
          {type.includes('black') && (
            <TouchIconWrap>
              <TouchIcon />
            </TouchIconWrap>
          )}
        </>
      )}
    </CardElement>
  );
};

export default DraggableCard;