import React from 'react';
import resolveClassName from '../../util/resolveClassName';
import classNames from './SplitFlapBoard.scss';

interface ISplitFlapBoardProps {
  /** Message the split flap board shall display */
  message: string;
  /** True to start the animation */
  start: boolean;
  /** Size of one split flap module, default of 40px */
  size?: number;
  /** Duration of one transition animation */
  duration?: number;
}

const SplitFlapBoard: React.FunctionComponent<ISplitFlapBoardProps> = ({
  message,
  start,
  size,
  duration,
}: ISplitFlapBoardProps) => {
  const classesMain = {
    name: 'split-flap',
    modifiers: [],
  };
  const classesTopNext = {
    name: 'top-next',
    modifiers: [],
  };
  const classesTopCurrent = {
    name: 'top-current',
    modifiers: ['stop', 'animate'],
  };
  const classesBottomCurrent = {
    name: 'bottom-current',
    modifiers: [],
  };
  const classesBottomNext = {
    name: 'bottom-next',
    modifiers: ['stop', 'animate'],
  };

  const typeSet = [
    ' ',
    'A',
    'B',
    'C',
    'D',
    'E',
    'F',
    'G',
    'H',
    'I',
    'J',
    'K',
    'L',
    'M',
    'N',
    'O',
    'P',
    'Q',
    'R',
    'S',
    'T',
    'U',
    'V',
    'W',
    'X',
    'Y',
    'Z',
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    '0',
  ];

  const [animate, setAnimate] = React.useState(false);
  const currentCharacter = React.useRef<number[]>(Array(message.length).fill(0));
  const nextCharacter = React.useRef<number[]>(Array(message.length).fill(1));
  const flapStop = React.useRef<boolean[]>(Array(message.length).fill(false));
  const timeout = React.useRef<NodeJS.Timeout>();

  const animation = () => {
    for (let i = 0; i < currentCharacter.current.length; i++) {
      if (typeSet[currentCharacter.current[i]] !== message.split('')[i]) {
        currentCharacter.current[i] = nextCharacter.current[i];
        nextCharacter.current[i] = (nextCharacter.current[i] % 36) + 1;
        if (typeSet[currentCharacter.current[i]] === message.split('')[i]) {
          flapStop.current[i] = true;
        }
      }
    }

    setAnimate(false);

    if (!flapStop.current.reduce((acc, val) => acc && val)) {
      timeout.current = setTimeout(() => {
        setAnimate(true);
        timeout.current = setTimeout(animation, duration ? duration * 1000 : 2000);
      }, Math.max(25, Math.random() * 100));
    }
  };

  React.useEffect(() => {
    if (start) {
      setAnimate(true);
      timeout.current = setTimeout(animation, duration ? duration * 1000 : 2000);
    }
  }, [start]); //eslint-disable-line react-hooks/exhaustive-deps

  React.useEffect(() => {
    return () => clearTimeout(timeout.current);
  }, []);

  return (
    <div className={classNames.container}>
      {message.split('').map((char, index) => {
        return (
          <div
            key={`${char}-${index}`}
            className={resolveClassName(classNames, classesMain, {})}
            style={{
              width: size ?? null,
              height: size ?? null,
              lineHeight: size ? `${size}px` : null,
              fontSize: size ?? null,
              perspective: size ? size * 10 : null,
            }}
          >
            {/* TOP NEXT CHAR */}
            <div
              className={resolveClassName(classNames, classesTopNext, {})}
              style={{ borderRadius: size ? `${size / 8}px ${size / 8}px 0 0` : null }}
            >
              {typeSet[nextCharacter.current[index]]}
            </div>
            {/* TOP CUR CHAR */}
            <div
              className={resolveClassName(classNames, classesTopCurrent, { animate, stop: flapStop.current[index] })}
              style={{
                animationDuration: `${duration}s` ?? null,
                borderRadius: size ? `${size / 8}px ${size / 8}px 0 0` : null,
              }}
            >
              {typeSet[currentCharacter.current[index]]}
            </div>
            {/* BOTTOM CUR CHAR */}
            <div
              className={resolveClassName(classNames, classesBottomCurrent, {})}
              style={{ borderRadius: size ? `0 0 ${size / 8}px ${size / 8}px` : null }}
            >
              <span>{typeSet[currentCharacter.current[index]]}</span>
            </div>
            {/* BOTTOM NEXT CHAR */}
            <div
              className={resolveClassName(classNames, classesBottomNext, { animate, stop: flapStop.current[index] })}
              style={{
                animationDuration: `${duration}s` ?? null,
                borderRadius: size ? `0 0 ${size / 8}px ${size / 8}px` : null,
              }}
            >
              <span>{typeSet[nextCharacter.current[index]]}</span>
            </div>
          </div>
        );
      })}
    </div>
  );
};

export default SplitFlapBoard;
