import React, { useContext, useEffect } from 'react';
import { StyleSheet, View, Animated, Easing } from 'react-native';
import Svg, { Mask, Rect } from 'react-native-svg';
import LottieView from 'lottie-react-native';
import { GetIDContext, type Theme } from '../../contexts/getid-context';
import captureAnimationLottie from './assets/capturing.json';
import { throttle } from '../../utils/throttle';

interface InFrame {
  right: boolean;
  left: boolean;
  top: boolean;
  bottom: boolean;
}

export type DocumentOverlayProps = {
  inFrame?: InFrame;
  rect: {
    width: number;
    left: number;
    right: number;
    top: number;
    bottom: number;
    height: number;
  };
  isLoading?: boolean;
  isSaving?: boolean;
  AnimatedFrame?: boolean;
};

export type RectangleProps = {
  width: number;
  height: number;
  right: number;
  left: number;
  top: number;
  bottom: number;
  status: 'error' | 'success';
};

type AnimatedFrameProps = {
  theme?: Theme;
  inFrame?: InFrame;
  isSaving?: boolean;
};

enum KeyPath {
  TopLeft = 'Top Left',
  TopRight = 'Top Right',
  BottomLeft = 'Bottom Left',
  BottomRight = 'Bottom Right',
}

const AnimatedFrame = ({ theme, inFrame, isSaving }: AnimatedFrameProps) => {
  const themeColor = theme?.cameraFrameColor as string;
  const baseColor = themeColor;
  const errorColor = theme?.errorColor as string;
  const successColor = theme?.successColor as string;

  const captureAnimationLottieRef = React.useRef<LottieView>(null);
  const [shouldPlay, setShouldPlay] = React.useState(false);
  const shouldPlayRef = React.useRef(shouldPlay);
  const isPlaying = React.useRef(false);

  const animationProgress = React.useRef(new Animated.Value(0));
  const animationControl = React.useRef(
    Animated.loop(
      Animated.timing(animationProgress.current, {
        toValue: 1,
        duration: 800,
        easing: Easing.linear,
        useNativeDriver: false,
      })
    )
  );

  const [colorFilters, setColorFilters] = React.useState([
    {
      keypath: '**',
      color: baseColor,
    },
  ]);

  useEffect(() => {
    if (isSaving) return;

    const topLeft = !!(inFrame?.top && inFrame?.left);
    const topRight = !!(inFrame?.top && inFrame?.right);
    const bottomLeft = !!(inFrame?.bottom && inFrame?.left);
    const bottomRight = !!(inFrame?.bottom && inFrame?.right);
    const allInframe = topLeft && topRight && bottomLeft && bottomRight;

    setShouldPlay(!allInframe);

    setColorFilters([
      {
        keypath: KeyPath.TopLeft,
        color: topLeft ? successColor : errorColor,
      },
      {
        keypath: KeyPath.TopRight,
        color: topRight ? successColor : errorColor,
      },
      {
        keypath: KeyPath.BottomLeft,
        color: bottomLeft ? successColor : errorColor,
      },
      {
        keypath: KeyPath.BottomRight,
        color: bottomRight ? successColor : errorColor,
      },
    ]);
  }, [errorColor, inFrame, isSaving, successColor]);

  useEffect(() => {
    setShouldPlay(!isSaving);
    if (isSaving) {
      setColorFilters(
        Object.values(KeyPath).map((value) => ({
          keypath: value,
          color: successColor,
        }))
      );
    }
  }, [isSaving, successColor]);

  const playAnimation = () => {
    animationControl.current.start();
    isPlaying.current = true;
  };

  const stopAnimation = () => {
    animationProgress.current.stopAnimation();
    isPlaying.current = false;
  };

  const toggleAnimation = throttle((play: boolean) => {
    if (play && !isPlaying.current) playAnimation();
    if (!play && isPlaying.current) stopAnimation();
  }, 1000);

  useEffect(() => {
    shouldPlayRef.current = shouldPlay;

    shouldPlay && toggleAnimation(true);
  }, [shouldPlay, toggleAnimation]);

  useEffect(() => {
    animationProgress.current.addListener(({ value }) => {
      if (value === 1 && !shouldPlayRef.current) toggleAnimation(false);
    });
  }, [toggleAnimation]);

  return (
    <View style={styles.animatedFrameWrapper}>
      <LottieView
        ref={captureAnimationLottieRef}
        progress={animationProgress.current}
        source={captureAnimationLottie}
        colorFilters={colorFilters}
      />
    </View>
  );
};

export type Point = { x: number; y: number };
export type QuadranglesProps = {
  quadrangles: Point[][];
};

const quadrangleColors = ['red', 'green', 'blue'];

// Draws the points of quadrangles on the screen
export const Quadrangles = (props: QuadranglesProps) => {
  return (
    <View style={styles.container}>
      <Svg height="100%" width="100%">
        <Mask id="mask" x="0" y="0" height="100%" width="100%">
          <Rect height="100%" width="100%" fill="white" />
        </Mask>
        <Rect height="100%" width="100%" fill="#00000000" mask="url(#mask)" />
        {props.quadrangles.flatMap((quadrangle, i) =>
          quadrangle.map((point) => (
            <Rect
              key={`${point.x},${point.y}`}
              x={point.x - 2}
              y={point.y - 2}
              width={5}
              height={5}
              fill={quadrangleColors[i % quadrangleColors.length]}
            />
          ))
        )}
      </Svg>
    </View>
  );
};

export const DocumentOverlay = (props: DocumentOverlayProps) => {
  const { width, height, top, left, right } = props.rect;
  const fullWidth = right + left;
  const widthPercent = (width * 100) / fullWidth;
  const context = useContext(GetIDContext);
  const overlayColor = context?.theme.cameraOverlayBackgroundColor;

  return (
    <View style={styles.container}>
      <Svg height="100%" width="100%">
        <Mask id="mask" x="0" y="0" height="100%" width="100%">
          <Rect height="100%" width="100%" fill="white" />
          <Rect
            x={left}
            y={top}
            rx="22"
            ry="22"
            width={width}
            height={height}
            fill="black"
          />
        </Mask>
        <Rect
          height="100%"
          width="100%"
          fill={overlayColor}
          mask="url(#mask)"
        />
      </Svg>
      <View style={styles.frameWrapper}>
        <View
          style={{
            ...styles.frame,
            width: `${widthPercent}%`,
            height: height,
          }}
        >
          <AnimatedFrame
            inFrame={props.inFrame}
            theme={context?.theme}
            isSaving={props.isSaving}
          />

          {props.isLoading && (
            <View style={styles.scanningAnimationWrapper}>
              <LottieView
                source={require('./assets/scanline.json')}
                resizeMode="cover"
                autoPlay
                loop
                style={styles.scanningAnimation}
              />
            </View>
          )}
        </View>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    display: 'flex',
    zIndex: 2,
  },
  frameWrapper: {
    position: 'absolute',
    top: 0,
    bottom: 0,
    display: 'flex',
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    width: '100%',
    height: '100%',
  },
  frame: {
    justifyContent: 'center',
    borderStyle: 'solid',
    borderRadius: 22,
    alignItems: 'center',
  },
  scanningAnimationWrapper: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    display: 'flex',
    borderRadius: 18,
    overflow: 'hidden',
  },
  scanningAnimation: {
    flex: 1,
  },
  animatedFrameWrapper: {
    transform: [{ scale: 1.35 }],
    width: '100%',
    height: '100%',
  },
});
