import CameraRoll from '@react-native-community/cameraroll';
import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
import {RouteProp} from '@react-navigation/core';
import {useFocusEffect} from '@react-navigation/native';
import {StackNavigationProp} from '@react-navigation/stack';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {Modal, StyleSheet, TouchableOpacity, View} from 'react-native';
import {CameraType, FlashMode, RNCamera} from 'react-native-camera';
import {AnimatedCircularProgress} from 'react-native-circular-progress';
import CloseIcon from '../../assets/ionicons/close-outline.svg';
import {FlashButton, FlipButton, GalleryIcon} from '../../components';
import {MAX_VIDEO_RECORDING_DURATION, TAGG_PURPLE} from '../../constants';
import {MainStackParams} from '../../routes';
import {HeaderHeight, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
import {showGIFFailureAlert, takePicture, takeVideo} from '../../utils/camera';

type CameraScreenRouteProps = RouteProp<MainStackParams, 'CameraScreen'>;
export type CameraScreenNavigationProps = StackNavigationProp<
  MainStackParams,
  'CameraScreen'
>;
interface CameraScreenProps {
  route: CameraScreenRouteProps;
  navigation: CameraScreenNavigationProps;
}
const CameraScreen: React.FC<CameraScreenProps> = ({route, navigation}) => {
  const {screenType, selectedCategory} = route.params;
  const cameraRef = useRef<RNCamera>(null);
  const tabBarHeight = useBottomTabBarHeight();
  const [cameraType, setCameraType] = useState<keyof CameraType>('back');
  const [flashMode, setFlashMode] = useState<keyof FlashMode>('off');
  const [mostRecentPhoto, setMostRecentPhoto] = useState<string>('');
  const [recordingStarted, setRecordingStarted] = useState<boolean>(false);
  const [showCaptureButtons, setShowCaptureButtons] = useState<boolean>(false);
  const [showCamera, setShowCamera] = useState<boolean>(true);

  const stopVideoRecording = async () => {
    if (await cameraRef.current?.isRecording()) {
      cameraRef.current?.stopRecording();
    }
  };

  useFocusEffect(
    useCallback(() => {
      navigation.dangerouslyGetParent()?.setOptions({
        tabBarVisible: false,
      });
      setRecordingStarted(false);
      setShowCaptureButtons(true);
      setShowCamera(true);
      return () => {
        setTimeout(() => {
          setShowCamera(false);
        }, 500);
      };
    }, [navigation]),
  );

  /*
   *  Chooses the last picture from gallery to display as the gallery button icon
   */
  useEffect(() => {
    CameraRoll.getPhotos({first: 1})
      .then((lastPhoto) => {
        if (lastPhoto.edges.length > 0) {
          const image = lastPhoto.edges[0].node.image;
          setMostRecentPhoto(image.uri);
        }
      })
      .catch((_err) =>
        console.log('Unable to fetch preview photo for gallery'),
      );
  }, []);

  const navigateToEditMedia = (uri: string) => {
    navigation.navigate('EditMedia', {
      screenType,
      media: {
        uri,
        isVideo: !(
          uri.endsWith('jpg') ||
          uri.endsWith('JPG') ||
          uri.endsWith('PNG') ||
          uri.endsWith('png') ||
          uri.endsWith('GIF') ||
          uri.endsWith('gif')
        ),
      },
      selectedCategory,
    });
  };

  const handleClose = () => {
    navigation.dangerouslyGetParent()?.setOptions({
      tabBarVisible: true,
    });
    navigation.goBack();
  };

  return (
    <View style={styles.container}>
      <Modal
        transparent={true}
        visible={
          recordingStarted && cameraType === 'front' && flashMode === 'on'
        }>
        <View style={styles.flashView} />
      </Modal>
      <TouchableOpacity style={styles.closeButton} onPress={handleClose}>
        <CloseIcon height={25} width={25} color={'white'} />
      </TouchableOpacity>
      <FlashButton flashMode={flashMode} setFlashMode={setFlashMode} />
      {showCamera && (
        <RNCamera
          ref={cameraRef}
          style={styles.camera}
          type={cameraType}
          flashMode={
            flashMode === 'on' && recordingStarted && cameraType === 'back'
              ? 'torch'
              : flashMode
          }
          onDoubleTap={() => {
            if (showCaptureButtons) {
              setCameraType(cameraType === 'front' ? 'back' : 'front');
            }
          }}
          onRecordingStart={() => setRecordingStarted(true)}
        />
      )}
      {showCaptureButtons && (
        <View style={[styles.bottomContainer, {bottom: tabBarHeight}]}>
          <FlipButton cameraType={cameraType} setCameraType={setCameraType} />
          <TouchableOpacity
            style={
              recordingStarted
                ? styles.captureButtonVideoContainer
                : styles.captureButtonContainer
            }
            activeOpacity={1}
            onLongPress={async () => {
              await stopVideoRecording();
              takeVideo(cameraRef, (vid) => navigateToEditMedia(vid.uri));
            }}
            onPressOut={async () => {
              setShowCaptureButtons(false);
              if (
                recordingStarted &&
                (await cameraRef.current?.isRecording())
              ) {
                cameraRef.current?.stopRecording();
              } else {
                takePicture(cameraRef, (pic) => navigateToEditMedia(pic.uri));
              }
              setRecordingStarted(false);
            }}
            onPress={async () => {
              if (showCaptureButtons) {
                setShowCaptureButtons(false);
              }
              takePicture(cameraRef, (pic) => navigateToEditMedia(pic.uri));
              await stopVideoRecording();
            }}>
            <View style={styles.captureButton} />
          </TouchableOpacity>
          {recordingStarted && (
            <AnimatedCircularProgress
              size={95}
              width={6}
              fill={100}
              rotation={0}
              duration={(MAX_VIDEO_RECORDING_DURATION + 1) * 1000} // an extra second for UI to load
              tintColor={TAGG_PURPLE}
              style={styles.bottomContainer}
              lineCap={'round'}
            />
          )}
          <View style={styles.bottomRightContainer}>
            <GalleryIcon
              mostRecentPhotoUri={mostRecentPhoto}
              callback={(media) => {
                const filename = media.filename;
                if (
                  filename &&
                  (filename.endsWith('gif') || filename.endsWith('GIF'))
                ) {
                  showGIFFailureAlert(() => navigateToEditMedia(media.path));
                } else {
                  navigateToEditMedia(media.path);
                }
              }}
            />
          </View>
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  camera: {
    flex: 1,
    justifyContent: 'space-between',
  },
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: 'black',
  },
  flashView: {
    width: SCREEN_WIDTH,
    height: SCREEN_HEIGHT,
    backgroundColor: '#fff',
    opacity: 0.5,
  },
  captureButtonVideoContainer: {
    alignSelf: 'center',
    backgroundColor: 'transparent',
    borderRadius: 100,
    borderWidth: 15,
    borderColor: 'rgba(255,255,255,0.3)',
    width: 93,
    height: 93,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  captureButtonContainer: {
    alignSelf: 'center',
    backgroundColor: 'transparent',
    borderRadius: 100,
    borderWidth: 4,
    borderColor: '#fff',
    width: 93,
    height: 93,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  captureButton: {
    backgroundColor: '#fff',
    width: 68,
    height: 68,
    borderRadius: 74,
  },
  closeButton: {
    position: 'absolute',
    top: 0,
    paddingTop: HeaderHeight,
    zIndex: 1,
    marginLeft: '5%',
  },
  bottomContainer: {
    position: 'absolute',
    width: SCREEN_WIDTH,
    flexDirection: 'row',
    justifyContent: 'center',
  },
  bottomRightContainer: {
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    width: (SCREEN_WIDTH - 100) / 2,
  },
});

export default CameraScreen;
