/* eslint-disable jsx-a11y/alt-text */
/* eslint-disable @next/next/no-img-element */
import { Image as ImageI } from '../../models/common';
import styles from './InitialLoader.module.scss';
import { motion, useAnimation } from 'framer-motion';
import { useEffect, useRef, useState } from 'react';
import { useDispatch } from 'react-redux';
import {
  setOverflow,
  setShow,
} from '../../redux/reducers/themeReducer/themeActions';
import {
  displayLoader,
  setImagesContainerHeight,
} from '../../redux/reducers/initialLoaderReducer/initialLoaderActions';
import { ThemeOverflow } from '../../redux/reducers/themeReducer/model';
import { hideInitialLoader, isInitialLoaderVisible } from '../../api/storage';
import Image from '../Image';
import { useMediaQuery } from 'react-responsive';

type Delay = {
  delay: number;
};

interface Props {
  title: string;
  images: ImageI[];
}
let timeout: number;
let factor: number = 1;
let damping: number = 0;

const percVariants = {
  initial: {
    y: '0%',
    opacity: 1,
  },
  hide: ({ delay = 0 }: Delay) => ({
    opacity: 0,
    y: '-200%',
    transition: {
      delay,
      duration: 0.4,
    },
  }),
};

const spanVariants = {
  initial: {
    y: '0%',
    opacity: 1,
  },
  hide: ({ delay = 0.14 }: Delay) => ({
    opacity: 0,
    y: '-200%',
    transition: {
      delay,
      duration: 0.4,
    },
  }),
};

const strongVariants = {
  initial: {
    y: '0%',
    opacity: 1,
  },
  hide: ({ delay = 0.28 }: Delay) => ({
    opacity: 0,
    y: '-200%',
    transition: {
      delay,
      duration: 0.4,
    },
  }),
};

const imagesContainerVariant = {
  initial: ({ initialHeight }: { initialHeight: number }) => ({
    y: initialHeight,
  }),
  show: ({ height, duration = 4.2 }: { height: number; duration: number }) => ({
    y: process.browser ? -height : 0,
    transition: {
      duration,
      ease: [0.42, 0, 1, 1],
    },
  }),
};

const imagesRowVariants = {
  initial: ({ initialX }: { initialX: string }) => ({
    x: initialX,
  }),
  show: ({
    endX,
    delay,
    duration = 4,
  }: {
    endX: string;
    delay: number;
    duration: number;
  }) => ({
    x: endX,
    transition: {
      duration,
      delay,
    },
  }),
};

const createImageGroups = (
  arr: ImageI[],
  numOfRows: number,
  imagesPerRow: number
): ImageI[][] => {
  return new Array(numOfRows)
    .fill('')
    .map((_, i) => arr.slice(i * imagesPerRow, (i + 1) * imagesPerRow));
};

const InitialLoader = (props: Props) => {
  const isVisible = isInitialLoaderVisible();
  const { title, images } = props;
  const dispatch = useDispatch();
  const imageGroups = createImageGroups(images, 3, 4);
  const [progress, setProgress] = useState(0);
  const progressAnimation = useAnimation();
  const textAnimation = useAnimation();
  const imagesAnimation = useAnimation();
  const imagesContainerRef = useRef<HTMLDivElement | null>(null);
  const [text, setText] = useState<ChildNode | null>();
  const [hide, setHide] = useState(true);
  const mql = process.browser
    ? window.matchMedia('(min-width: 900px)')
    : undefined;

  const isDesktop = useMediaQuery({ query: '(min-width: 900px)' });

  let imageWidth = 250;
  let imageHeight = 175;

  if (isDesktop){
    imageWidth = 697;
    imageHeight = 487;
  }

  useEffect(() => {
    if (imagesContainerRef?.current?.offsetHeight) {
      dispatch(
        setImagesContainerHeight(imagesContainerRef?.current?.offsetHeight)
      );
      imagesAnimation.set('initial');
    }
  }, [imagesContainerRef?.current?.offsetHeight]);

  useEffect(() => {
    damping = Math.floor(Math.random() * 25) + 6;
    factor = Math.max((100 - progress) / damping, 1);
    const _progress = progress + factor;
    const diff = _progress - progress;
    const updatedProgress = () => {
      if (progress >= 100) {
        window.clearTimeout(timeout);
        dispatch(setShow());
        textAnimation.start('hide');
        imagesAnimation.start('show');
        progressAnimation.start({
          width: `0%`,
          transition: {
            duration: 1,
            /* ease: 'linear', */
          },
        });
      } else {
        progressAnimation.start({
          width: `${_progress.toFixed(0)}%`,
          transition: {
            duration: 0.035 * diff,
            /* ease: 'linear', */
          },
        });
        setProgress(Number(_progress.toFixed(0)));
      }
    };
    if (imagesContainerRef?.current?.offsetHeight && isVisible) {
      window.requestAnimationFrame(() => {
        timeout = window.setTimeout(updatedProgress, 35 * diff);
      });
    }
  }, [progress, imagesContainerRef?.current?.offsetHeight]);

  useEffect(() => {
    if (!isVisible) {
      dispatch(setOverflow(ThemeOverflow.VISIBLE));
      hideInitialLoader();
      dispatch(displayLoader(false));
    } else {
      setHide(false);
    }
  }, []);

  useEffect(() => {
    const text: ChildNode | null = process.browser
      ? new DOMParser().parseFromString(title, 'text/html').body.childNodes[0]
      : null;

    setText(text);
  }, []);

  return (
    <div className={`${styles.loader} ${hide ? styles.hidden : ''}`}>
      <div className={styles.textContainer}>
        <div className={styles.phrase}>
          {text?.childNodes &&
            [...text?.childNodes].map((node, id) => {
              if (node?.nodeName === '#text')
                return (
                  <motion.span
                    animate={textAnimation}
                    variants={spanVariants}
                    custom={{ delay: mql?.matches ? 0.14 : 0 }}
                    initial={'initial'}
                    key={id}
                  >
                    {node.nodeValue}
                  </motion.span>
                );
              if (node?.nodeName === 'STRONG')
                return (
                  <motion.strong
                    animate={textAnimation}
                    variants={strongVariants}
                    custom={{ delay: mql?.matches ? 0.28 : 0 }}
                    initial={'initial'}
                    key={id}
                  >
                    {(node as HTMLElement).innerHTML}
                  </motion.strong>
                );
            })}
        </div>
        <motion.div
          className={styles.perc}
          animate={textAnimation}
          custom={{ delay: mql?.matches ? 0 : 0.4 }}
          variants={percVariants}
          initial={'initial'}
        >
          {progress}%<br />
        </motion.div>
      </div>
      <div
        className={`${styles.progressBarContainer} ${
          progress === 100 ? styles.reverse : ''
        }`}
      >
        <motion.div
          className={styles.progressBar}
          animate={progressAnimation}
        />
      </div>
      <motion.div
        className={styles.imagesContainer}
        animate={imagesAnimation}
        variants={imagesContainerVariant}
        onAnimationComplete={() => {
          dispatch(setOverflow(ThemeOverflow.VISIBLE));
          setHide(true);
          dispatch(displayLoader(false));
          document.body.classList.remove('loading');
        }}
        ref={imagesContainerRef}
        custom={{
          initialHeight: process.browser ? window.innerHeight : '100%',
          height: imagesContainerRef?.current?.offsetHeight,
          duration: mql?.matches ? 4.2 : 3.2,
        }}
      >
        {imageGroups.map((images, key) => {
          const custom =
            key % 2 === 0
              ? { initialX: '24px', endX: '-34.24%' }
              : { initialX: '-34.24%', endX: '24px' };

          return (
            <motion.div
              className={styles.imagesRow}
              key={key}
              custom={{
                ...custom,
                delay: 0.5 * key,
                duration: mql?.matches ? 4.2 : 3.5,
              }}
              animate={imagesAnimation}
              variants={imagesRowVariants}
            >
              {images.map((image, id) => (
                <Image
                  alt={image?.alt || ''}
                  image={{
                    ...image,
                    width: imageWidth,
                    height: imageHeight,
                    layout: 'responsive',
                    loading: 'eager',
                    quality: 50,
                    priority: true
                  }}
                  key={id}
                />
              ))}
            </motion.div>
          );
        })}
      </motion.div>
    </div>
  );
};

export default InitialLoader;
