import {useCallback, useEffect, useRef, useState} from 'react';
import {
  useSharedValue,
  useAnimatedStyle,
  withTiming,
  Easing,
} from 'react-native-reanimated';

import {VideoStatus} from '../interfaces';

const CONTROLS_HIDE_DELAY = 2500;
const MANUAL_PLAY_DELAY = 1500;
const ANIMATION_DURATION = 250;

interface UseVideoControlsVisibilityProps {
  status: VideoStatus;
  hideDuringAutoplay?: boolean;
}

enum VisibilityState {
  Visible = 'VISIBLE',
  Hidden = 'HIDDEN',
  ManualPlay = 'MANUAL_PLAY',
}

export function useVideoControlsVisibility({
  status,
  hideDuringAutoplay = false,
}: UseVideoControlsVisibilityProps) {
  const [visibilityState, setVisibilityState] = useState<VisibilityState>(
    VisibilityState.Visible,
  );
  const hideTimeoutRef = useRef<Nullable<NodeJS.Timeout>>(null);

  const containerOpacity = useSharedValue(1);
  const animatedStyle = useAnimatedStyle(() => ({
    opacity: containerOpacity.value,
  }));

  const clearHideTimeout = useCallback(() => {
    if (hideTimeoutRef.current) {
      clearTimeout(hideTimeoutRef.current);
      hideTimeoutRef.current = null;
    }
  }, []);

  const showControls = useCallback(() => {
    setVisibilityState(VisibilityState.Visible);
  }, []);

  const hideControls = useCallback(() => {
    setVisibilityState(VisibilityState.Hidden);
  }, []);

  const startAutoHide = useCallback(() => {
    if (status === VideoStatus.Playing) {
      clearHideTimeout();
      hideTimeoutRef.current = setTimeout(() => {
        hideControls();
      }, CONTROLS_HIDE_DELAY);
    }
  }, [status, clearHideTimeout, hideControls]);

  const showWithAutoHide = useCallback(() => {
    showControls();
    startAutoHide();
  }, [showControls, startAutoHide]);

  const onInteraction = useCallback(() => {
    if (status === VideoStatus.Playing) {
      showWithAutoHide();
    } else {
      showControls();
    }
  }, [status, showWithAutoHide, showControls]);

  const onToggleControls = useCallback(() => {
    if (status === VideoStatus.Playing) {
      if (visibilityState === VisibilityState.Visible) {
        hideControls();
        clearHideTimeout();
      } else {
        showWithAutoHide();
      }
    } else {
      showControls();
    }
  }, [
    status,
    visibilityState,
    hideControls,
    clearHideTimeout,
    showWithAutoHide,
    showControls,
  ]);

  const onManualPlayOrReplay = useCallback(() => {
    setVisibilityState(VisibilityState.ManualPlay);
    clearHideTimeout();
    hideTimeoutRef.current = setTimeout(() => {
      hideControls();
    }, MANUAL_PLAY_DELAY);
  }, [clearHideTimeout, hideControls]);

  useEffect(() => {
    if (status === VideoStatus.Playing) {
      if (visibilityState === VisibilityState.Hidden && !hideDuringAutoplay) {
        // Show controls initially when video starts playing (unless autoplay hiding)
        showWithAutoHide();
      }
    } else {
      // Always show controls when video is paused, loading, or finished
      clearHideTimeout();
      showControls();
    }
  }, [
    status,
    visibilityState,
    hideDuringAutoplay,
    clearHideTimeout,
    hideControls,
    showWithAutoHide,
    showControls,
  ]);

  useEffect(() => {
    const isVisible =
      visibilityState === VisibilityState.Visible ||
      visibilityState === VisibilityState.ManualPlay;

    containerOpacity.value = withTiming(isVisible ? 1 : 0, {
      duration: ANIMATION_DURATION,
      easing: isVisible ? Easing.out(Easing.cubic) : Easing.in(Easing.cubic),
    });
  }, [visibilityState, containerOpacity]);

  useEffect(() => {
    return clearHideTimeout;
  }, [clearHideTimeout]);

  return {
    showControls:
      visibilityState === VisibilityState.Visible ||
      visibilityState === VisibilityState.ManualPlay,
    onInteraction,
    onToggleControls,
    onManualPlayOrReplay,
    animatedStyle,
  };
}
