import { Fragment } from 'react';
import { motion, useAnimation } from 'framer-motion';
import { useEffect, useState } from 'react';
import styles from './Links.module.scss';

export enum WavyIconSize {
  LARGE = 'large',
  SMALL = 'small',
}

type Props = {
  children: JSX.Element | JSX.Element[] | string | string[];
  href?: string;
  isIconFirst?: boolean;
  iconClassName?: string;
  hasArrow?: boolean;
  size?: WavyIconSize;
  loading?: boolean;
};

let points: number[] = [];
let counter = 0;
let speed = 2;

function createPoints(width: number) {
  const amp = width !== 30 ? 10 : 50;
  const freq = width !== 30 ? 15 : 20;
  let x,
    y,
    step = 0;
  points = [];
  const yDiv = width !== 30 ? 200 : 200;
  const xDiv = width !== 30 ? 150 : 150;
  for (x = 0; x <= width; x++) {
    x < width / 2 ? step-- : step++;
    y = (step / yDiv) * amp * Math.sin(((x + counter) / xDiv) * freq);
    points.push(x, y);
  }

  return points.join(' ');
}

const circleVariants = {
  enter: {
    pathLength: 1,
    transition: {
      duration: 0.7,
      delay: 0.5,
    },
  },
  initial: {
    pathLength: 0,
  },
  exit: {
    pathLength: 0,
    transition: {
      duration: 0.7,
    },
  },
};
// eslint-disable-next-line react/display-name
const WavyLink = (props: Props): JSX.Element | null => {
  const {
    children,
    hasArrow = true,
    isIconFirst,
    iconClassName = '',
    size,
    loading,
  } = props;
  const _iconClassName = `${styles.wave} ${iconClassName} ${
    isIconFirst ? '' : styles.marginLeftSm
  }`;
  const arr: string[] = [];
  const [points, setPoints] = useState<string[]>([]);
  const width = size === WavyIconSize.SMALL ? 30 : 125;
  const wavePoints =
    size !== WavyIconSize.SMALL
      ? '0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0 16 0 17 0 18 0 19 0 20 0 21 0 22 0 23 0 24 0 25 0 26 0 27 0 28 0 29 0 30 0 31 0 32 0 33 0 34 0 35 0 36 0 37 0 38 0 39 0 40 0 41 0 42 0 43 0 44 0 45 0 46 0 47 0 48 0 49 0 50 0 51 0 52 0 53 0 54 0 55 0 56 0 57 0 58 0 59 0 60 0 61 0 62 0 63 0 64 0 65 0 66 0 67 0 68 0 69 0 70 0 71 0 72 0 73 0 74 0 75 0 76 0 77 0 78 0 79 0 80 0 81 0 82 0 83 0 84 0 85 0 86 0 87 0 88 0 89 0 90 0 91 0 92 0 93 0 94 0 95 0 96 0 97 0 98 0 99 0 100 0 101 0 102 0 103 0 104 0 105 0 106 0 107 0 108 0 109 0 110 0 111 0 112 0 113 0 114 0 115 0 116 0 117 0 118 0 119 0 120 0 121 0 122 0 123 0 124 0 125 0'
      : '0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0 16 0 17 0 18 0 19 0 20 0 21 0 22 0 23 0 24 0 25 0 26 0 27 0 28 0 29 0 30 0';
  const arrowPoints =
    size !== WavyIconSize.SMALL
      ? '123 11 126 5.52595675 123 0'
      : '27 11 31 5.5 27 0';

  const controls = useAnimation();
  const lineControls = useAnimation();
  const [lineControlsState, setLineControlsState] = useState<string>();
  const controlsCircle = useAnimation();

  const lineContainerVariants = {
    exit: {
      x: '200%',
      transition: {
        duration: 0.7,
      },
    },
    enter: {
      x: '0%',
      transition: {
        duration: 0.7,
        delay: 0.5,
      },
    },
  };

  const lineVariants = {
    hover: {
      points: points,
      transition: {
        repeat: Infinity,
        type: 'spring',
        duration: 1.2,
      },
    },
    default: {
      points: wavePoints,
      transition: {
        repeat: undefined,
        type: 'spring',
        duration: 0.2,
      },
    },
  };

  useEffect(() => {
    const max = size === WavyIconSize.SMALL ? 48 : 96;
    for (var i = 0; i < max; i++) {
      arr.push(createPoints(width).replaceAll(',', ' '));
      counter += speed;
    }
    setPoints(arr);
  }, []);

  useEffect(() => {
    if (loading) {
      controls.start('exit');
      controlsCircle.set({ transform: 'rotateY(0deg)' });
      controlsCircle.start('enter');
    } else {
      controlsCircle.set({ transform: 'rotateY(180deg)' });
      controlsCircle.start('exit');
      controls.set({
        x: '-100%',
      });
      controls.start('enter');
    }
  }, [loading]);

  const icon =
    points?.length > 0 ? (
      <motion.span
        className={_iconClassName}
        variants={lineContainerVariants}
        animate={controls}
        initial={'enter'}
      >
        <svg
          id="wave"
          width={`${width + 2}px`}
          viewBox={`0 0 ${width + 2} 13`}
          style={{ overflow: 'visible' }}
        >
          <motion.polyline
            stroke="#2766C4"
            fill="none"
            strokeWidth="1px"
            variants={lineVariants}
            style={{ transform: 'translate(0, 5.8px)' }}
            points={wavePoints}
            animate={lineControls}
          ></motion.polyline>
          <polyline
            id="Path"
            stroke="#2766C4"
            fill="none"
            points={arrowPoints}
            style={{ transform: 'translate(0, 0)' }}
          ></polyline>
        </svg>
      </motion.span>
    ) : null;

  return points?.length > 0 ? (
    <motion.span
      className={` ${
        isIconFirst ? styles.wavy_link : styles.wavy_link_reverse
      } ${!hasArrow ? styles.table : 'h5_links'} ${
        size ? styles['wavy_link-icon--' + size] : ''
      }`}
      onMouseOver={() => {
        if (lineControlsState !== 'hover') {
          setLineControlsState('hover');
          lineControls.start('hover');
        }
      }}
      onMouseLeave={() => {
        setLineControlsState('default');
        lineControls.start('default');
      }}
    >
      {isIconFirst ? icon : null}
      {loading && (
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="24"
          height="24"
          viewBox="0 0 24 24"
          className={styles.circle}
        >
          <g id="Web_1920_1" data-name="Web 1920 – 1">
            <g id="Path_1" data-name="Path 1" fill="none">
              <motion.path
                d="M11.5,0.5A11.5,11.5,0.5,1,1,0.5,11.5,11.5,11.5,0.5,0,1,11.5,0.5Z"
                stroke="#2766c4"
                animate={controlsCircle}
                initial={'exit'}
                variants={circleVariants}
              />
            </g>
          </g>
        </svg>
      )}
      <span>{children}</span>
      {!isIconFirst ? icon : null}
    </motion.span>
  ) : null;
};

export default WavyLink;
