import React, { useState, useEffect, useMemo } from 'react';
import { View, ActivityIndicator, TouchableOpacity, Platform, Image } from 'react-native';
import { useEvent } from 'expo';
import { useVideoPlayer, VideoView, type VideoSource } from 'expo-video';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { FileSystem } from 'src/utils';
import { Colors } from 'src/theme';
import { CACHED_ATTACHMENTS_DIR } from 'src/constants/constants';
import { API_HOST, APP_VERSION } from 'src/constants';

type RenderMessageVideoProps = {
  props: any;
  token: string;
  currentUserId: number;
  onLongPress: (currentMessage: any, props: any) => any;
};

const MAX_RETRY = 3;

const RenderMessageVideo = ({
  props,
  token,
  currentUserId,
  onLongPress
}: RenderMessageVideoProps) => {
  const { currentMessage } = props;
  if (!currentMessage?.video) return null;

  const leftMessage = currentMessage?.user?._id !== currentUserId;

  const [videoUri, setVideoUri] = useState<string | null>(null);
  const [retryCount, setRetryCount] = useState(0);

  const [showPoster, setShowPoster] = useState(true);
  const [hasStarted, setHasStarted] = useState(false);

  const downloadVideo = async (videoUrl: string) => {
    if (!videoUrl.startsWith('https')) {
      setVideoUri(videoUrl);
      return videoUrl;
    }

    try {
      const dirExist = await FileSystem.getInfoAsync(CACHED_ATTACHMENTS_DIR);
      if (!dirExist.exists) {
        await FileSystem.makeDirectoryAsync(CACHED_ATTACHMENTS_DIR, { intermediates: true });
      }

      const filename =
        currentMessage?.attachment?.filename ?? `video-${currentMessage?._id ?? ''}.mp4`;
      const videoPath = `${CACHED_ATTACHMENTS_DIR}${filename}`;

      const videoExists = await FileSystem.getInfoAsync(videoPath);
      if (videoExists.exists) {
        if ((videoExists.size ?? 0) < 1024) {
          await FileSystem.deleteAsync(videoPath, { idempotent: true });
        } else {
          try {
            await FileSystem.readAsStringAsync(videoPath, {
              encoding: FileSystem.EncodingType.Base64
            });
            setVideoUri(videoPath);
            return videoPath;
          } catch {
            await FileSystem.deleteAsync(videoPath, { idempotent: true });
          }
        }
      }

      const downloadResult = await FileSystem.downloadAsync(videoUrl, videoPath, {
        headers: {
          Nmtoken: token,
          'App-Version': APP_VERSION,
          Platform: Platform.OS
        }
      });

      setVideoUri(downloadResult.uri);
      return downloadResult.uri;
    } catch (error) {
      console.error('Error downloading video:', error);
      return null;
    }
  };

  useEffect(() => {
    const loadVideo = async () => {
      if (currentMessage?.video && !currentMessage?.isSending) {
        setShowPoster(true);
        await downloadVideo(currentMessage.video);
      }
    };
    loadVideo();
  }, [currentMessage.video, currentMessage.isSending]);

  const player = useVideoPlayer(null, (p) => {
    p.loop = false;
    p.muted = false;
    p.volume = 1;
    p.timeUpdateEventInterval = 0.5;
  });

  useEffect(() => {
    (async () => {
      if (videoUri) {
        const source: VideoSource = { uri: videoUri };
        await player.replaceAsync(source);
      }
    })();
  }, [videoUri, player]);

  const { status, error } = useEvent(player, 'statusChange', { status: player.status });
  const { isPlaying } = useEvent(player, 'playingChange', { isPlaying: player.playing });

  const isBuffering = status !== 'readyToPlay';
  const isVideoLoaded = status === 'readyToPlay';

  useEffect(() => {
    if (status === 'readyToPlay') setShowPoster(false);
  }, [status]);

  useEffect(() => {
    (async () => {
      if ((status === 'error' || !!error) && retryCount < MAX_RETRY && videoUri) {
        try {
          await FileSystem.deleteAsync(videoUri, { idempotent: true });
        } catch {}
        const newUri = await downloadVideo(currentMessage.video);
        if (newUri) {
          setRetryCount((c) => c + 1);
          setShowPoster(true);
        }
      }
    })();
  }, [status, error]);

  const posterUri = useMemo(
    () =>
      currentMessage?.attachment?.attachment_small_url
        ? API_HOST + currentMessage.attachment.attachment_small_url
        : null,
    [currentMessage]
  );

  const handlePlayPress = async () => {
    if (isVideoLoaded) {
      setHasStarted(true);
      await player.play();
    }
  };

  return (
    <View style={{ width: 200, height: 200, padding: 6, borderRadius: 10, overflow: 'hidden' }}>
      {posterUri && showPoster && (
        <Image
          source={{ uri: posterUri }}
          style={{ position: 'absolute', top: 6, left: 6, right: 6, bottom: 6, borderRadius: 10 }}
          resizeMode="cover"
        />
      )}

      {videoUri ? (
        <VideoView
          style={{ flex: 1, borderRadius: 10 }}
          player={player}
          contentFit="contain"
          nativeControls
          fullscreenOptions={{
            enable: true
          }}
          allowsPictureInPicture={true}
        />
      ) : null}

      {isBuffering && (
        <View
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            alignItems: 'center',
            justifyContent: 'center'
          }}
        >
          <ActivityIndicator
            size="large"
            color={leftMessage ? Colors.DARK_BLUE : Colors.FILL_LIGHT}
          />
        </View>
      )}

      {!hasStarted && !isBuffering && videoUri && (
        <TouchableOpacity
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            alignItems: 'center',
            justifyContent: 'center'
          }}
          onPress={handlePlayPress}
          onLongPress={() => onLongPress(currentMessage, props)}
        >
          <View style={{ backgroundColor: 'rgba(15, 63, 79, 0.4)', borderRadius: 50 }}>
            <MaterialCommunityIcons name="play" size={60} color={Colors.WHITE} />
          </View>
        </TouchableOpacity>
      )}
    </View>
  );
};

export default RenderMessageVideo;
