import {RouteProp} from '@react-navigation/core';
import {StackNavigationProp} from '@react-navigation/stack';
import React, {useEffect, useRef, useState} from 'react';
import {Image, StyleSheet, TouchableOpacity, View} from 'react-native';
import {normalize} from 'react-native-elements';
import ImageZoom, {IOnMove} from 'react-native-image-pan-zoom';
import PhotoManipulator from 'react-native-photo-manipulator';
import CloseIcon from '../../assets/ionicons/close-outline.svg';
import {MainStackParams} from '../../routes';
import {
  cropVideo,
  HeaderHeight,
  SCREEN_HEIGHT,
  SCREEN_WIDTH,
} from '../../utils';
import {TaggSquareButton} from '../common';
import ReactNativeZoomableView from '@dudigital/react-native-zoomable-view/src/ReactNativeZoomableView';
import Video from 'react-native-video';

type ZoomInCropperRouteProps = RouteProp<MainStackParams, 'ZoomInCropper'>;
type ZoomInCropperNavigationProps = StackNavigationProp<
  MainStackParams,
  'ZoomInCropper'
>;
interface ZoomInCropperProps {
  route: ZoomInCropperRouteProps;
  navigation: ZoomInCropperNavigationProps;
}

export const ZoomInCropper: React.FC<ZoomInCropperProps> = ({
  route,
  navigation,
}) => {
  const {screenType, media, selectedCategory} = route.params;
  const [aspectRatio, setAspectRatio] = useState<number>(1);
  // width and height of video, if video
  const [origDimensions, setOrigDimensions] = useState<number[]>([0, 0]);
  const vidRef = useRef(null);

  // Stores the coordinates of the cropped image
  const [x0, setX0] = useState<number>();
  const [x1, setX1] = useState<number>();
  const [y0, setY0] = useState<number>();
  const [y1, setY1] = useState<number>();

  // Stores crop information for video
  const [videoCrop, setVideoCrop] = useState<{
    cropWidth?: number;
    cropHeight?: number;
    cropOffsetX?: number;
    cropOffsetY?: number;
  }>({});

  const checkIfUriImage = (uri: string) => {
    return (
      uri.endsWith('jpg') ||
      uri.endsWith('JPG') ||
      uri.endsWith('PNG') ||
      uri.endsWith('png') ||
      uri.endsWith('GIF') ||
      uri.endsWith('gif')
    );
  };

  // Setting original aspect ratio of image
  useEffect(() => {
    if (media.uri && checkIfUriImage(media.uri)) {
      Image.getSize(
        media.uri,
        (w, h) => {
          setAspectRatio(w / h);
        },
        (err) => console.log(err),
      );
    } else if (media.uri && !checkIfUriImage(media.uri)) {
      const tempVideoCrop = {...videoCrop};
      tempVideoCrop.cropWidth = origDimensions[0];
      tempVideoCrop.cropHeight = origDimensions[1];
      setVideoCrop(tempVideoCrop);
    }
  }, []);

  // Possible need to delay setting aspect ratio of video until loaded
  useEffect(() => {
    if (media.uri && !checkIfUriImage(media.uri)) {
      const tempVideoCrop = {...videoCrop};
      tempVideoCrop.cropWidth = origDimensions[0];
      tempVideoCrop.cropHeight = origDimensions[1];
      setVideoCrop(tempVideoCrop);
    }
  }, [origDimensions]);

  // Crops original image based of (x0, y0) and (x1, y1) coordinates
  const handleNext = () => {
    if (checkIfUriImage(media.uri)) {
      if (
        x0 !== undefined &&
        x1 !== undefined &&
        y0 !== undefined &&
        y1 !== undefined
      ) {
        PhotoManipulator.crop(media.uri, {
          x: x0,
          y: y1,
          width: Math.abs(x0 - x1),
          height: Math.abs(y0 - y1),
        })
          .then((croppedURL) => {
            navigation.navigate('CaptionScreen', {
              screenType,
              media: {
                uri: croppedURL,
                isVideo: false,
              },
            });
          })
          .catch((err) => console.log('err: ', err));
      } else if (
        x0 === undefined &&
        x1 === undefined &&
        y0 === undefined &&
        y1 === undefined
      ) {
        navigation.navigate('CaptionScreen', {
          screenType,
          media,
        });
      }
    } else {
      if (!videoCrop.cropHeight || !videoCrop.cropWidth) {
        const tempVideoCrop = {...videoCrop};
        tempVideoCrop.cropWidth = origDimensions[0];
        tempVideoCrop.cropHeight = origDimensions[1];
        setVideoCrop(tempVideoCrop);
      }
      cropVideo(
        media.uri,
        (croppedURL: string) => {
          navigation.navigate('CaptionScreen', {
            screenType,
            media: {
              uri: croppedURL,
              isVideo: true,
            },
            selectedCategory,
          });
        },
        videoCrop,
      );
    }
  };

  // for whenever the video is altered by the user
  const onVideoMove = (zoomableEvent: any) => {
    const {originalHeight, originalWidth} = zoomableEvent;

    let cropWidth = 0;
    let cropHeight = 0;
    let cropOffsetX = 0;
    let cropOffsetY = 0;

    if (vidRef !== null && vidRef.current !== null) {
      vidRef.current.measure(
        (
          _x: number,
          _y: number,
          width: number,
          height: number,
          pageX: number,
          pageY: number,
        ) => {
          // width
          cropWidth = origDimensions[0] * (originalWidth / width);

          // offsetX
          cropOffsetX = -1 * origDimensions[0] * (pageX / width);
          if (cropOffsetX < 0) {
            cropOffsetX = 0;
          } else if (cropOffsetX + cropWidth > origDimensions[0] - 1) {
            cropOffsetX = origDimensions[0] - cropWidth - 1;
          }

          // height
          if (
            height * (SCREEN_WIDTH / aspectRatio / originalHeight) >
            SCREEN_HEIGHT
          ) {
            const superHeight = width / aspectRatio;
            cropHeight = origDimensions[1] * (originalHeight / superHeight);

            // offsetY
            const topDeadZone = (height - superHeight) / 2;
            const offsetY = topDeadZone + pageY;
            cropOffsetY = -1 * origDimensions[1] * (offsetY / superHeight);
            if (cropOffsetY < 0) {
              cropOffsetY = 0;
            } else if (cropOffsetY + cropHeight > origDimensions[1]) {
              cropOffsetY = origDimensions[1] - cropHeight - 1;
            }
          } else {
            cropHeight = origDimensions[1];
          }
          const tempVideoCrop = {...videoCrop};
          tempVideoCrop.cropWidth = cropWidth;
          tempVideoCrop.cropHeight = cropHeight;
          tempVideoCrop.cropOffsetX = cropOffsetX;
          tempVideoCrop.cropOffsetY = cropOffsetY;
          setVideoCrop(tempVideoCrop);
        },
      );
    }
  };

  /* Records (x0, y0) and (x1, y1) coordinates used later for cropping,
   * based on(x, y) - the center of the image and scale of zoom
   */
  const onMove = (position: IOnMove) => {
    Image.getSize(
      media.uri,
      (w, h) => {
        const x = position.positionX;
        const y = position.positionY;
        const scale = position.scale;
        const screen_ratio = SCREEN_HEIGHT / SCREEN_WIDTH;
        let tempx0 = w / 2 - x * (w / SCREEN_WIDTH) - w / 2 / scale;
        let tempx1 = w / 2 - x * (w / SCREEN_WIDTH) + w / 2 / scale;
        if (tempx0 < 0) {
          tempx0 = 0;
        }
        if (tempx1 > w) {
          tempx1 = w;
        }
        const x_distance = Math.abs(tempx1 - tempx0);
        const y_distance = screen_ratio * x_distance;
        let tempy0 = h / 2 - y * (h / SCREEN_HEIGHT) + y_distance / 2;
        let tempy1 = h / 2 - y * (h / SCREEN_HEIGHT) - y_distance / 2;
        if (tempy0 > h) {
          tempy0 = h;
        }
        if (tempy1 < 0) {
          tempy1 = 0;
        }
        setX0(tempx0);
        setX1(tempx1);
        setY0(tempy0);
        setY1(tempy1);
      },
      (err) => console.log(err),
    );
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        style={styles.closeButton}
        onPress={() => navigation.goBack()}>
        <CloseIcon height={25} width={25} color={'white'} />
      </TouchableOpacity>
      {checkIfUriImage(media.uri) ? (
        <ImageZoom
          style={styles.zoomView}
          cropWidth={SCREEN_WIDTH}
          cropHeight={SCREEN_HEIGHT}
          imageWidth={SCREEN_WIDTH}
          imageHeight={SCREEN_WIDTH / aspectRatio}
          onMove={onMove}>
          <Image
            style={{width: SCREEN_WIDTH, height: SCREEN_WIDTH / aspectRatio}}
            source={{
              uri: media.uri,
            }}
          />
        </ImageZoom>
      ) : (
        <ReactNativeZoomableView
          maxZoom={10}
          minZoom={1}
          zoomStep={0.5}
          initialZoom={1}
          bindToBorders={true}
          // onZoomAfter={this.logOutZoomState}
          onDoubleTapAfter={(
            _1: any,
            _2: any,
            zoomableViewEventObject: any,
          ) => {
            onVideoMove(zoomableViewEventObject);
          }}
          onShiftingAfter={(_1: any, _2: any, zoomableViewEventObject: any) => {
            onVideoMove(zoomableViewEventObject);
          }}
          onShiftingEnd={(_1: any, _2: any, zoomableViewEventObject: any) => {
            onVideoMove(zoomableViewEventObject);
          }}
          onZoomAfter={(_1: any, _2: any, zoomableViewEventObject: any) => {
            onVideoMove(zoomableViewEventObject);
          }}
          onZoomEnd={(_1: any, _2: any, zoomableViewEventObject: any) => {
            onVideoMove(zoomableViewEventObject);
          }}
          style={styles.zoomView}>
          <View style={styles.videoParent} ref={vidRef}>
            <Video
              source={{uri: media.uri}}
              volume={1}
              style={[
                styles.media,
                {
                  height: SCREEN_WIDTH / aspectRatio,
                },
              ]}
              repeat={true}
              resizeMode={'contain'}
              onLoad={(response) => {
                const {width, height} = response.naturalSize;
                setOrigDimensions([width, height]);
                setAspectRatio(width / height);
              }}
            />
          </View>
        </ReactNativeZoomableView>
      )}

      <TaggSquareButton
        onPress={handleNext}
        title={'Next'}
        buttonStyle={'normal'}
        buttonColor={'blue'}
        labelColor={'white'}
        style={styles.button}
        labelStyle={styles.buttonLabel}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: 'black',
    height: SCREEN_HEIGHT,
    width: SCREEN_WIDTH,
  },
  closeButton: {
    position: 'absolute',
    top: 0,
    paddingTop: HeaderHeight,
    zIndex: 1,
    marginLeft: '5%',
  },
  button: {
    zIndex: 1,
    position: 'absolute',
    bottom: normalize(20),
    right: normalize(15),
    width: normalize(108),
    height: normalize(25),
    borderRadius: 10,
  },
  buttonLabel: {
    fontWeight: '700',
    fontSize: normalize(15),
    lineHeight: normalize(17.8),
    letterSpacing: normalize(1.3),
    textAlign: 'center',
  },
  media: {
    zIndex: 0,
    flex: 1,
  },
  videoParent: {
    flex: 1,
  },
  zoomView: {
    backgroundColor: 'black',
    flex: 1,
  },
});
