import React, { useCallback, useMemo, useRef, useEffect } from "react";

import ReactPlayer from "react-player";

import handle from "@enact/core/handle";

var handledMediaEventsMap = [
  "onReady",
  "onStart",
  "onPlay",
  "onProgress",
  "onDuration",
  "onPause",
  "onBuffer",
  "onBufferEnd",
  "onSeek",
  "onEnded",
  "onError",
];

export default function TReactPlayer({
  mediaEventsMap = handledMediaEventsMap,
  videoRef,
  url,
  ...rest
}) {
  const playerRef = useRef(null);

  const handleEvent = useCallback(
    (type) => (ev) => {
      if (type === "onReady") {
        if (videoRef) {
          const videoNode = playerRef.current.getInternalPlayer();
          videoRef(videoNode);
          if (
            videoNode.tagName &&
            !Object.prototype.hasOwnProperty.call(videoNode, "proportionPlayed")
          ) {
            Object.defineProperties(videoNode, {
              error: {
                get: function () {
                  return videoNode.networkState === videoNode.NETWORK_NO_SOURCE;
                },
              },
              loading: {
                get: function () {
                  return videoNode.readyState < videoNode.HAVE_ENOUGH_DATA;
                },
              },
              proportionLoaded: {
                get: function () {
                  return (
                    videoNode.buffered.length &&
                    videoNode.buffered.end(videoNode.buffered.length - 1) /
                      videoNode.duration
                  );
                },
              },
              proportionPlayed: {
                get: function () {
                  return videoNode.currentTime / videoNode.duration;
                },
              },
            });
          } else if (
            !Object.prototype.hasOwnProperty.call(videoNode, "proportionPlayed")
          ) {
            videoNode.play = videoNode.playVideo;
            videoNode.pause = videoNode.pauseVideo;
            videoNode.seek = videoNode.seekTo;
            Object.defineProperties(videoNode, {
              currentTime: {
                get: function () {
                  return videoNode.getCurrentTime();
                },
                set: function (time) {
                  videoNode.seekTo(time);
                },
              },
              duration: {
                get: function () {
                  return videoNode.getDuration();
                },
              },
              paused: {
                get: function () {
                  return videoNode.getPlayerState() !== 1;
                },
              },
              error: {
                get: function () {
                  return !!videoNode?.playerInfo?.videoData?.errorCode;
                },
              },
              loading: {
                get: function () {
                  return !videoNode?.playerInfo?.videoData?.isPlayable; //todo
                },
              },
              proportionLoaded: {
                get: function () {
                  return videoNode?.getVideoBytesLoaded() ?? 0;
                },
              },
              proportionPlayed: {
                get: function () {
                  const duration = videoNode.getDuration();
                  return duration ? videoNode.getCurrentTime() / duration : 0;
                },
              },
              playbackRate: {
                get: function () {
                  return videoNode?.playerInfo?.playbackRate;
                },
                set: function (playbackRate) {
                  if (videoNode && videoNode.setPlaybackRate) {
                    videoNode.setPlaybackRate(playbackRate);
                  }
                },
              },
            });
          }
        }
        handle.forward("onLoadStart", { type, ev }, rest);
      }
      handle.forward("onUpdate", { type, ev }, rest);
    },
    [videoRef]
  );

  const handledMediaEvents = useMemo(() => {
    const events = {};
    for (let i = 0; i < mediaEventsMap.length; i++) {
      const eventName = mediaEventsMap[i];
      events[eventName] = handleEvent(eventName);
    }
    return events;
  }, [handleEvent, mediaEventsMap]);

  useEffect(() => {
    return () => {
      const videoNode = playerRef.current?.getInternalPlayer();
      if (videoNode && videoNode.pause) {
        videoNode.pause();
        videoNode.src = "";
        videoNode.srcObject = null;
      }
    };
  }, []);

  return (
    <ReactPlayer
      ref={playerRef}
      url={url}
      progressInterval={1000}
      {...handledMediaEvents}
      {...rest}
      playsinline // Add playsinline attribute here
    />
  );
}
