import {useCallback, useEffect, useMemo} from 'react';
import {View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {Typography, Image} from '@components';
import {formatSecondsToTime} from '@modules/chat/utils';
import {IconPlayVideo} from '@modules/chats/components';
import {useMediaAsset, useVideoSource} from '@modules/chats/hooks';
import {VideoPlayerPool} from '@modules/chats/instances/VideoPlayerPool';
import {useIsVisibleVideoAsset} from '@modules/chats/instances/VisibleVideoAssets';
import {
  getChatImage,
  MESSAGE_VIDEO_THUMBNAIL_WIDTH,
} from '@modules/chats/utils';
import {useTheme} from '@shared/theme';

import {Remaining} from '../Remaining';
import {getTileSizeStyle, ImageSize, tileStyles} from '../tileStyles';
import {styles} from './styles';

interface Props {
  size: ImageSize;
  messageId: string;
  attachmentId: number;
  remaining?: number;
  onPress: (attachmentId: number) => void;
}

export function VideoRenderer({
  size,
  messageId,
  attachmentId,
  remaining,
  onPress,
}: Props) {
  const {theme} = useTheme();
  const {t} = useTranslation();

  const {imageUrl, videoUrl, videoDurationMs} = useMediaAsset(
    messageId,
    attachmentId,
  );

  const thumbUrl = getChatImage.thumbnail(imageUrl, {
    width: MESSAGE_VIDEO_THUMBNAIL_WIDTH,
  });

  // `useVideoSource` stabilizes the source identity across renders
  // (auth-header refresh otherwise churns it). Without that, the effect
  // below re-runs every render and the pool's release/acquire cadence
  // outpaces React's effect-ordering — the slot's refCount never settles
  // at 0, so reuse never kicks in.
  const source = useVideoSource(videoUrl);

  // Only preload when the tile is actually in the FlatList's viewport —
  // off-screen tiles that the FlatList keeps mounted for recycling
  // shouldn't burn a native player slot or network buffering. Acquire is
  // deferred to `requestIdleCallback` so a fast scroll doesn't pile
  // synchronous native work onto the render thread; the cleanup tracks
  // whether the deferred acquire actually ran so we release exactly the
  // right number of times.
  const isVisible = useIsVisibleVideoAsset(attachmentId);
  useEffect(() => {
    if (!source || !isVisible) return;
    let acquired = false;
    let cancelled = false;
    const idleId = requestIdleCallback(() => {
      if (cancelled) return;
      VideoPlayerPool.acquire(messageId, attachmentId, source);
      acquired = true;
    });
    return () => {
      cancelled = true;
      if (typeof cancelIdleCallback === 'function') {
        cancelIdleCallback(idleId);
      }
      if (acquired) {
        VideoPlayerPool.release(messageId, attachmentId);
      }
    };
  }, [source, messageId, attachmentId, isVisible]);

  const sizeStyle = getTileSizeStyle(size);

  const onItemPress = useCallback(() => {
    onPress(attachmentId);
  }, [onPress, attachmentId]);

  const formattedDuration = useMemo(() => {
    const durationMs = videoDurationMs ?? 0;
    return durationMs
      ? formatSecondsToTime(Math.round(durationMs / 1000), {minutesFormat: 'm'})
      : '';
  }, [videoDurationMs]);

  return (
    <View style={tileStyles.container} accessible={false}>
      <Image
        source={{uri: thumbUrl}}
        useRNGHPressable
        withAuthHeader
        enableCache
        timeout={15_000}
        style={[
          {backgroundColor: theme.background.elements.inverted},
          sizeStyle,
        ]}
        loaderType="none"
        onPress={onItemPress}
        // TODO: Add accessibility label for video renderer
        accessibilityLabel={t('chat.files.video_one')}
      />
      <View style={[sizeStyle, styles.absoluteContainer]} pointerEvents="none">
        <View style={styles.durationContainer}>
          <Typography
            variant="xxxs"
            color={theme.text.neutral.inverted}
            style={styles.durationText}>
            {formattedDuration}
          </Typography>
        </View>
        {remaining ? (
          <Remaining count={remaining} sizeStyle={sizeStyle} />
        ) : (
          <IconPlayVideo />
        )}
      </View>
    </View>
  );
}
