import { ITouchEvent, View } from "@tarojs/components";
import { RoundItem } from "../RoundItem";
import Taro from "@tarojs/taro";
import {
  forwardRef,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from "react";
import { useInterval } from "../../../../hooks/useInterval";
import "./index.scss";
import { SORT_MAP_ID } from "../../constants";

export interface SwiperProps {
  curSwiperItem: number;
  handleDetail(id: number): void;
  setCurSwiperItem(num: number): void;
}

export interface SwiperMethods {
  toNext(): void;
  toPrev(): void;
  setIsRunning(v: boolean): void;
}

const SIGHT_COUNT = 26;
const Big_R = (500 * Taro.getSystemInfoSync().windowWidth) / 750;
const MIN_R = (150 * Taro.getSystemInfoSync().windowWidth) / 750;

const getItemStack = () => {
  const stack: number[] = [];
  for (let i = 0; i <= 13; i++) {
    stack.push(i);
  }
  return stack;
};

export const Swiper = forwardRef<SwiperMethods, SwiperProps>(
  ({ curSwiperItem, setCurSwiperItem, handleDetail }, ref) => {
    const [itemStack, setItemStack] = useState(getItemStack());
    const touchStartX = useRef(0);
    const moving = useRef(false);
    const [isRunning, setIsRunning] = useState(false);

    const getNextItem = (curIndex: number, length: number) => {
      return (curIndex + 1) % length;
    };
    const getPreviousItem = (curIndex: number, length: number) => {
      return (curIndex - 1 + length) % length;
    };
    const getIndicesRelative = (curIndex: number, length: number) => {
      const nextIndex = getNextItem(curIndex, length);
      const nextThreeIndices = [nextIndex];
      for (let i = 1; i < 1; i++) {
        nextThreeIndices.push(getNextItem(nextThreeIndices[i - 1], length));
      }

      const previousIndex = getPreviousItem(curIndex, length);
      const previousThreeIndices = [previousIndex];
      for (let i = 1; i <= 2; i++) {
        previousThreeIndices.push(
          getPreviousItem(previousThreeIndices[i - 1], length)
        );
      }

      return [nextThreeIndices, previousThreeIndices];
    };

    const handleTouchStart = (e: ITouchEvent) => {
      setIsRunning(false);
      touchStartX.current = e.changedTouches[0].clientX;
    };
    const handleTouchEnd = (e: ITouchEvent) => {
      const touchEndX = e.changedTouches[0].clientX;
      const deltaX = touchEndX - touchStartX.current;

      if (deltaX > 50) {
        toPrev();
      } else if (deltaX < -50) {
        toNext();
      }
    };

    const toggleHandler = (fn: Function) => {
      if (moving.current) return;

      setIsRunning(false);
      moving.current = true;
      fn();
    };

    const toNext = () => {
      toggleHandler(() => {
        const temp = [...itemStack];
        const swiperItem = getNextItem(curSwiperItem, SIGHT_COUNT);
        temp.shift();
        temp.push(getNextItem(curSwiperItem + 3, SIGHT_COUNT));
        setItemStack(temp);
        setCurSwiperItem(swiperItem);
      });
    };

    const toPrev = () => {
      toggleHandler(() => {
        const temp = [...itemStack];
        const swiperItem = getPreviousItem(curSwiperItem, SIGHT_COUNT);
        temp.pop();
        temp.unshift(getPreviousItem(itemStack[0], SIGHT_COUNT));
        setItemStack(temp);
        setCurSwiperItem(swiperItem);
      });
    };

    const [nexts, prevs] = useMemo(
      () => getIndicesRelative(curSwiperItem, SIGHT_COUNT),
      [curSwiperItem]
    );
    const activeId = getPreviousItem(curSwiperItem, SIGHT_COUNT);

    const nearIds = [
      getPreviousItem(activeId, SIGHT_COUNT),
      getNextItem(activeId, SIGHT_COUNT),
    ];

    useImperativeHandle(ref, () => {
      return {
        toNext,
        toPrev,
        setIsRunning,
      };
    });

    useInterval(toNext, isRunning ? 5000 : null);

    return (
      <View
        className="sights"
        onTouchStart={handleTouchStart}
        onTouchEnd={handleTouchEnd}
      >
        {itemStack.map((id, idx) => {
          const realId = SORT_MAP_ID[id + 1 > 25 ? 0 : id + 1];
          const show =
            [...nexts, ...prevs].includes(id) || id === curSwiperItem;
          const isActive = activeId === id;

          return (
            show && (
              <RoundItem
                key={id}
                id={realId}
                angle={(360 / 12) * idx}
                bigR={Big_R}
                minR={MIN_R}
                isActive={isActive}
                isNear={nearIds.includes(id)}
                onClick={handleDetail.bind(undefined, realId)}
                onActLoaded={() => {
                  setTimeout(() => {
                    moving.current = false;
                    setIsRunning(true);
                  }, 500);
                }}
              />
            )
          );
        })}
      </View>
    );
  }
);
