/* eslint-disable import/no-duplicates */
import type { VideoProperties } from '@react-native-bedrock/native/react-native-video';
import type VideoRef from '@react-native-bedrock/native/react-native-video';
import { forwardRef, Ref, useMemo, useState } from 'react';
import { Animated, Platform } from 'react-native';
import { Video as RNVideo } from './instance';
import { isAvailable } from './instance';
import { useVisibility } from '../visibility';

const AnimatedRNVideo = Animated.createAnimatedComponent(RNVideo);

// Add this interface declaration
interface VideoComponent extends React.ForwardRefExoticComponent<VideoProperties & React.RefAttributes<VideoRef>> {
  isAvailable: boolean;
}

/**
 * @public
 * @category UI
 * @name OnAudioFocusChanged
 * @description 오디오 포커스가 변경될 때 호출되는 콜백 함수에요. `muted` 가 `false` 인 경우에 필수로 구현해야해요.
 *
 * @param {Object} event - 오디오 포커스 정보를 담고 있는 이벤트 객체예요.
 * @param {boolean} event.hasAudioFocus - 비디오 컴포넌트가 오디오 포커스를 가지고 있는지 여부를 나타내요.
 */
type OnAudioFocusChanged = NonNullable<VideoProperties['onAudioFocusChanged']>;

type Props =
  | (VideoProperties & { muted: true })
  | (VideoProperties & { muted: false; onAudioFocusChanged: OnAudioFocusChanged });

/**
 * @public
 * @category UI
 * @name RNVideoRef
 * @description
 * `react-native-video`의 ref 타입이에요.
 */
export type RNVideoRef = VideoRef;

/**
 * @public
 * @name Video
 * @category UI
 * @description
 * Video 컴포넌트는 다른 앱에서 음악을 재생 중일 때, 토스 앱에서 그 음악을 중지시키지 않도록 오디오 포커스를 제어하는 로직이 구현된 컴포넌트에요. 앱의 상태에 따라 자동으로 재생하거나 일시정지해요. 예를 들어, 앱이 백그라운드로 전환되면 비디오가 자동으로 일시정지돼요.
 *
 * ::: warning
 * Video 컴포넌트는 [`react-native-video` 버전(6.0.0-alpha.6)](https://github.com/TheWidlarzGroup/react-native-video/tree/v6.0.0-alpha.6) 을 사용하고 있어요. 따라서 일부 타입이나 기능이 최신 버전과 호환되지 않을 수 있어요.
 * :::
 *
 * @property {boolean} [isAvailable] `Video` 컴포넌트를 사용할 수 있는지 확인하는 값이에요. 이 값을 확인해서 사용자가 비디오를 렌더링할 수 있는지 혹은 환경적 제약(예: 네트워크 연결 문제, 지원되지 않는 디바이스 등)으로 인해 비디오 기능을 사용할 수 없는지를 먼저 확인할 수 있어요. 이 값이 `false`라면, 비디오를 렌더링하지 않거나 대체 콘텐츠를 제공하는 등의 처리를 해야 해요.
 *
 * @param {VideoProperties} [props] [`react-native-video`](https://github.com/TheWidlarzGroup/react-native-video/tree/v6.0.0-alpha.6)에서 제공하는 속성들이에요.
 * @param {string} [props.source.uri] 재생할 비디오의 소스에요. 파일 경로나 URL을 설정할 수 있어요.
 * @param {boolean} [props.muted=false] 비디오의 음소거 상태를 제어해요. `true`면 비디오의 오디오가 음소거되고, `false`면 오디오가 재생돼요. 기본값은 `false`에요.
 * @param {boolean} [props.paused=false] 비디오 재생을 제어하는 속성이에요. `true`이면 비디오가 일시 정지되고, `false`이면 비디오가 재생돼요. 기본값은 `false`이고, 자동 재생돼요.
 * @param {OnAudioFocusChanged} [props.onAudioFocusChanged] 오디오 포커스가 변경될 때 호출되는 콜백 함수에요. `muted` 가 `false` 인 경우에 필수로 구현해야해요. 자세한 내용은 [OnAudioFocusChanged](/react-native/reference/react-native-bedrock/Types/OnAudioFocusChanged.html)를 참고해주세요.
 * @param {Ref<VideoRef>} ref 비디오 인스턴스에 접근하기 위한 ref 객체에요. 이 ref를 통해 비디오 인스턴스의 여러 메서드에 접근할 수 있어요.
 *
 * @returns {JSX.Element} 비디오를 렌더링하는 JSX 엘리먼트를 반환해요. `Animated`를 사용해 부드러운 애니메이션 효과를 포함한 비디오 재생을 제공해요.
 *
 * @see [react-native-video] https://github.com/react-native-video/react-native-video
 * 비디오 컴포넌트의 자세한 속성은 공식 문서를 참고해주세요.
 * @see [react-native-video-6.0.0-alpha.6] https://github.com/TheWidlarzGroup/react-native-video/releases/tag/v6.0.0-alpha.6
 * 현재 토스앱에 설치되어있는 버전의 소스코드에요.
 *
 * @example
 *
 * ### 비디오 자동재생 예제
 *
 * ```tsx
 * import { useRef } from 'react';
 * import { View } from 'react-native';
 * import { Video } from 'react-native-bedrock';
 *
 * export function VideoExample() {
 *   const videoRef = useRef(null);
 *
 *   return (
 *     <View>
 *       <Video
 *         ref={videoRef}
 *         source={{ uri: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4' }}
 *         muted={true}
 *         paused={false}
 *         resizeMode="cover"
 *         style={{ width: 300, height: 200, borderWidth: 1 }}
 *       />
 *     </View>
 *   );
 * }
 * ```
 */
export const Video = forwardRef((props: Props, ref: Ref<VideoRef>) => {
  const [isFocused, setIsFocused] = useState(props.muted || props.paused);
  const visible = useVisibility();

  // onAudioFocusChanged로 서비스에서 직접 포커스 상태를 관리하는 경우가 아니라면, 내부 상태를 바탕으로 paused 값을 제어합니다.
  const paused = useMemo(
    () => !visible || props.paused || (!props.onAudioFocusChanged && !isFocused),
    [props.onAudioFocusChanged, props.paused, visible, isFocused]
  );

  const disableFocus = props.muted || props.paused;
  const mixWithOthers = props.muted ? 'mix' : undefined;

  return (
    <AnimatedRNVideo
      ref={ref}
      /**
       * @name enableDecoderFallback
       * @description
       * 안드로이드 기기에서 16개까지는 하드웨어 가속 코덱을 사용해서 잘 렌더링 되는데,
       * 그 이상부터는 렌더링이 안되는 이슈가 있다.
       * 따라서 소프트웨어 코덱으로 fallback 하도록 저리를 해놓고 이렇게 prop을 추가해서 적용할 수 있게했다.
       * 이것을 false로 하는 경우는 없을것으로 가정하고 인터페이스에는 노출을 하지 않는다.
       */
      progressUpdateInterval={16}
      disableFocus={Platform.OS === 'ios' ? false : disableFocus}
      playWhenInactive
      onAudioFocusChanged={({ hasAudioFocus }) => setIsFocused(hasAudioFocus)}
      {...props}
      enableDecoderFallback={true}
      paused={paused}
      mixWithOthers={mixWithOthers}
    />
  );
});

(Video as VideoComponent).isAvailable = isAvailable;
