import { motion } from 'framer-motion';
import { useRouter } from 'next/dist/client/router';
import { Fragment, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { setPreviousRoute } from '../../redux/reducers/routerReducer/routerActions';
import styles from './PageTransition.module.scss';

const pageTransitionItemsLength = 4;
const pageTransitionItems = [...Array(pageTransitionItemsLength)];

const numbers = [0.15, 0.2, 0.25, 0.3];

function shuffleArray(array: number[]) {
  for (var i = array.length - 1; i > 0; i--) {
    var j = Math.floor(Math.random() * (i + 1));
    var temp = array[i];
    array[i] = array[j];
    array[j] = temp;
  }
  return array;
}

const itemVariants = {
  open: {
    width: '100vw'
  },
  closed: {
    width: '0vw'
  }
};

const pVariants = {
  hide: {
    transition: {
      staggerChildren: 0.014,
      staggerDirection: 1,
      when: 'afterChildren'
    }
  },
  show: {
    transition: {
      when: 'beforeChildren',
      staggerChildren: 0.014,
      delayChildren: 0.5
    }
  }
};

const variants = {
  hide: {
    y: '101%',
    transition: {
      duration: 0.35,
      ease: [1, 0, 0.6, 0.09]
    }
  },
  show: {
    y: '0%',
    transition: {
      duration: 0.35,
      ease: [0.09, 0.6, 0, 1]
    }
  }
};

interface Props {
  phrases: string[];
}

const PageTransition = (props: Props): JSX.Element | null => {
  const router = useRouter();
  const dispatch = useDispatch();
  const [mounted, setMounted] = useState(false);
  const [phrase, setPhrase] = useState<HTMLElement | null>(null);
  const [loading, setLoading] = useState(false);
  const [show, setShow] = useState(false);
  const _shuffleArray = shuffleArray(numbers);
  const { phrases } = props;

  const nodes = phrase?.childNodes ? [...phrase?.childNodes] : [];
  let _id = 0;

  useEffect(() => {
    let startTime: number | null = null;
    const updatePhrase = () => {
      const text: HTMLElement | null = process.browser
        ? new DOMParser().parseFromString(
          phrases[Math.floor(Math.random() * (phrases?.length - 1 + 1))],
          'text/html'
        ).body
        : null;
      setPhrase(text);
    };
    const handleStart = () => {

      updatePhrase();
      setShow(true);
      setLoading(true);
      startTime = new Date().getTime();
      if (mounted) {
        setTimeout((() => {
          dispatch(setPreviousRoute(router.asPath));
        }), 1600);
      }
    };

    const handleComplete = () => {
      const now = new Date().getTime();
      const diff = startTime && now - startTime < 1600 ? (1600 - (now - startTime)) : 0;


      setTimeout((() => {

        setLoading(false);
        if (typeof window !== 'undefined') {
          // @ts-ignore
          window.gtag('event', 'login', { method: 'Google' });
          // @ts-ignore
          window.gtag('event', 'page_view', {
            page_path: router.asPath,
            page_location: window.location.href
          });
        }
      }), diff);
    };

    router.events.on('routeChangeStart', handleStart);
    router.events.on('routeChangeComplete', handleComplete);
    router.events.on('routeChangeError', handleComplete);

    return () => {
      router.events.off('routeChangeStart', handleStart);
      router.events.off('routeChangeComplete', handleComplete);
      router.events.off('routeChangeError', handleComplete);
    };
  }, []);

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted) return null;

  return (
    <div
      className={`${styles.container} ${
        loading ? styles.open : styles.closed
      } ${!show ? styles.hidden : ''}`}
    >
      {show &&
        pageTransitionItems.map((item, id) => (
          <motion.div
            key={id}
            className={styles.item}
            transition={{
              delay: loading ? _shuffleArray[id] : _shuffleArray[id] + 0.5,
              duration: 0.5
            }}
            animate={loading ? 'open' : 'closed'}
            variants={itemVariants}
            onAnimationComplete={() => {
              if (pageTransitionItems.length - 1 === id && !loading)
                setShow(false);
            }}
          />
        ))}

      {show && mounted && (
        <motion.div
          className={styles.text}
          initial='hide'
          animate={loading ? 'show' : 'hide'}
          variants={pVariants}
        >
          {nodes.map((childNode, id) => {
            const childNodes = [...childNode.childNodes];
            return childNodes.map((node, id) => {
              const isTextNode = node?.nodeName === '#text';
              const isStrongNode = node?.nodeName === 'STRONG';
              let text = node.nodeValue
                ? [...(node.nodeValue as string).split(' ')]
                : [];
              if (isStrongNode)
                text = [...(node as HTMLElement).innerHTML.split(' ')];
              return isTextNode ? (
                text.map((word, wordId) => (
                  <Fragment key={word}>
                    <span key={wordId} className={styles.word}>
                      {[...word].map((letter, letterId) => {
                        _id = _id + 1;
                        return (
                          <motion.span
                            variants={variants}
                            key={_id}
                            className={letter === ' ' ? styles.space : ''}
                          >
                            {letter}
                          </motion.span>
                        );
                      })}
                    </span>
                    {wordId !== text.length - 1 ? (
                      <span className={styles.space}> </span>
                    ) : null}
                  </Fragment>
                ))
              ) : isStrongNode ? (
                <strong key={id}>
                  {text.map((word, wordId) => (
                    <Fragment key={word}>
                      <span className={styles.word}>
                        {[...word].map((letter, letterId) => {
                          _id = _id + 1;
                          return (
                            <motion.span
                              variants={variants}
                              key={_id}
                              className={letter === ' ' ? styles.space : ''}
                            >
                              {letter}
                            </motion.span>
                          );
                        })}
                      </span>
                      {wordId !== text.length - 1 ? (
                        <span className={styles.space}> </span>
                      ) : null}
                    </Fragment>
                  ))}
                </strong>
              ) : null;
            });
          })}
        </motion.div>
      )}
    </div>
  );
};

export default PageTransition;
