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

import classNames from "classnames";
import { useDispatch } from "react-redux";

import { Job } from "@enact/core/util";
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import { setContainerLastFocusedElement } from "@enact/spotlight/src/container";

import dummyVtt from "../../../assets/mock/video.vtt";
import {
  changeAppStatus,
  changeLocalSettings,
  requestLiveSubtitle,
  sendBroadCast,
  setHidePopup,
} from "../../actions/commonActions";
import {
  sendLogGNB,
  sendLogLive,
  sendLogTotalRecommend,
  sendLogVOD,
} from "../../actions/logActions";
import {
  clearShopNowInfo,
  getHomeFullVideoInfo,
  getMainCategoryShowDetail,
  getMainLiveShow,
  getMainLiveShowNowProduct,
} from "../../actions/mainActions";
import * as PanelActions from "../../actions/panelActions";
import { updatePanel } from "../../actions/panelActions";
import {
  CLEAR_PLAYER_INFO,
  getChatLog,
  getSubTitle,
  startVideoPlayer,
} from "../../actions/playActions";
import { convertUtcToLocal } from "../../components/MediaPlayer/util";
import TPanel from "../../components/TPanel/TPanel";
import TPopUp from "../../components/TPopUp/TPopUp";
import Media from "../../components/VideoPlayer/Media";
import TReactPlayer from "../../components/VideoPlayer/TReactPlayer";
import { VideoPlayer } from "../../components/VideoPlayer/VideoPlayer";
import usePrevious from "../../hooks/usePrevious";
import useWhyDidYouUpdate from "../../hooks/useWhyDidYouUpdate";
import * as Config from "../../utils/Config";
import { ACTIVE_POPUP, panel_names } from "../../utils/Config";
import { $L, formatGMTString } from "../../utils/helperMethods";
import { SpotlightIds } from "../../utils/SpotlightIds";
import { removeDotAndColon } from "./PlayerItemCard/PlayerItemCard";
import PlayerOverlayChat from "./PlayerOverlay/PlayerOverlayChat";
import PlayerOverlayQRCode from "./PlayerOverlay/PlayerOverlayQRCode";
import css from "./PlayerPanel.module.less";
import PlayerTabButton from "./PlayerTabContents/TabButton/PlayerTabButton";
import TabContainer from "./PlayerTabContents/TabContainer";

const Container = SpotlightContainerDecorator(
  { enterTo: "default-element", preserveld: true },
  "div",
);

const findSelector = (selector, maxAttempts = 5, currentAttempts = 0) => {
  try {
    if (currentAttempts >= maxAttempts) {
      throw new Error("selector not found");
    }

    const initialSelector = document.querySelector(selector);

    if (initialSelector) {
      return initialSelector;
    } else {
      return findSelector(selector, maxAttempts, currentAttempts + 1);
    }
  } catch (error) {
    // console.error(error.message);
  }
};

const getLogTpNo = (type, nowMenu) => {
  if (type === "LIVE") {
    switch (nowMenu) {
      case Config.LOG_MENU.HOME_TOP:
        return Config.LOG_TP_NO.LIVE.HOME;
      // case Config.LOG_MENU.FEATURED_BRANDS_LIVE_CHANNELS:
      // return Config.LOG_TP_NO.LIVE.FEATURED_BRANDS;
      case Config.LOG_MENU.FULL_SHOP_NOW:
      case Config.LOG_MENU.FULL_YOU_MAY_LIKE:
      case Config.LOG_MENU.FULL_LIVE_CHANNELS:
        return Config.LOG_TP_NO.LIVE.FULL;
      default:
        return Config.LOG_TP_NO.LIVE.FEATURED_BRANDS;
    }
  } else if (type === "VOD") {
    switch (nowMenu) {
      case Config.LOG_MENU.HOME_TOP:
        return Config.LOG_TP_NO.VOD.HOME_VOD; // 153
      case Config.LOG_MENU.TRENDING_NOW_POPULAR_SHOWS:
        return Config.LOG_TP_NO.VOD.POPULAR_SHOWS_AND_HOT_PICKS; // 151
      case Config.LOG_MENU.FULL_SHOP_NOW:
      case Config.LOG_MENU.FULL_YOU_MAY_LIKE:
      case Config.LOG_MENU.FULL_FEATURED_SHOWS:
        return Config.LOG_TP_NO.VOD.FULL_VOD; // 150
      default:
        return;
    }
  } else if (type === "MEDIA") {
    switch (nowMenu) {
      case Config.LOG_MENU.HOME_TOP:
        return Config.LOG_TP_NO.VOD.HOME_VOD; // 153
      case Config.LOG_MENU.HOT_PICKS:
        return Config.LOG_TP_NO.VOD.POPULAR_SHOWS_AND_HOT_PICKS; // 151
      case Config.LOG_MENU.DETAIL_PAGE_BILLING_PRODUCT_DETAIL:
      case Config.LOG_MENU.DETAIL_PAGE_PRODUCT_DETAIL:
      case Config.LOG_MENU.DETAIL_PAGE_GROUP_DETAIL:
      case Config.LOG_MENU.DETAIL_PAGE_THEME_DETAIL:
      case Config.LOG_MENU.DETAIL_PAGE_TRAVEL_THEME_DETAIL:
        return Config.LOG_TP_NO.VOD.ITEM_DETAIL_MEDIA; // 156
      case Config.LOG_MENU.FULL:
        return Config.LOG_TP_NO.VOD.FULL_MEDIA; // 155
      default:
        return;
    }
  }
};

const YOUTUBECONFIG = {
  playerVars: {
    controls: 0, // 플레이어 컨트롤 표시
    autoplay: 1,
    disablekb: 1,
    enablejsapi: 1,
    listType: "user_uploads",
    fs: 0,
    rel: 0, // 관련 동영상 표시 안 함
    showinfo: 0,
    loop: 0,
    iv_load_policy: 3,
    modestbranding: 1,
    wmode: "opaque",
    cc_lang_pref: "en",
    cc_load_policy: 0,
    playsinline: 1,
  },
};

const INITIAL_TIMEOUT = 30000;
const REGULAR_TIMEOUT = 30000;
const TAB_CONTAINER_SPOTLIGHT_ID = "tab-container-spotlight-id";
const TARGET_EVENTS = ["mousemove", "keydown", "click"];

// last time error
const VIDEO_END_ACTION_DELAY = 1500;

const PlayerPanelNew = ({
  isTabActivated,
  panelInfo,
  isOnTop,
  spotlightId,
  ...props
}) => {
  const dispatch = useDispatch();
  const { USE_STATE, USE_SELECTOR } = useWhyDidYouUpdate(spotlightId, {
    isTabActivated,
    panelInfo,
    isOnTop,
    ...props,
  });

  const videoPlayer = useRef(null);
  const [playListInfo, setPlayListInfo] = USE_STATE("playListInfo", "");
  const [shopNowInfo, setShopNowInfo] = USE_STATE("shopNowInfo");
  const [backupInitialIndex, setBackupInitialIndex] = USE_STATE(
    "backupInitialIndex",
    0,
  );
  const [modalStyle, setModalStyle] = USE_STATE("modalStyle", {});
  const [modalScale, setModalScale] = USE_STATE("modalScale", 1);
  const [mediaId, setMediaId] = USE_STATE("mediaId", null);
  const [currentLiveTimeSeconds, setCurrentLiveTimeSeconds] = USE_STATE(
    "currentLiveTimeSeconds",
    1,
  );
  const [prevChannelIndex, setPrevChannelIndex] = USE_STATE(
    "prevChannelIndex",
    0,
  );
  const [sideContentsVisible, setSideContentsVisible] = USE_STATE(
    "sideContentsVisible",
    true,
  );
  const [currentTime, setCurrentTime] = USE_STATE("currentTime", 0);
  const [isInitialFocusOccurred, setIsInitialFocusOccurred] = USE_STATE(
    "isInitialFocusOccurred",
    false,
  );
  const [selectedIndex, setSelectedIndex] = USE_STATE(
    "selectedIndex",
    panelInfo.shptmBanrTpNm === "LIVE" ? null : 0,
  );
  const [isUpdate, setIsUpdate] = USE_STATE("isUpdate", false);
  const [isSubtitleActive, setIsSubtitleActive] = USE_STATE(
    "isSubtitleActive",
    true,
  );
  const [logStatus, setLogStatus] = USE_STATE("logStatus", {
    isModalLiveLogReady: false,
    isFullLiveLogReady: false,
    isDetailLiveLogReady: false,
    isModalVodLogReady: false,
    isFullVodLogReady: false,
    isDetailVodLogReady: false,
    isModalMediaLogReady: false,
    isFullMediaLogReady: false,
    isDetailMediaReady: false,
  });
  const [isVODPaused, setIsVODPaused] = USE_STATE("isVODPaused", false);

  const playerControl = USE_SELECTOR(
    "playerControl",
    (state) => state.home.playerControl,
  );
  const panels = USE_SELECTOR("panels", (state) => state.panels.panels);
  const chatData = USE_SELECTOR("chatData", (state) => state.play.chatData);

  const popupVisible = USE_SELECTOR(
    "popupVisible",
    (state) => state.common.popup.popupVisible,
  );
  const activePopup = USE_SELECTOR(
    "activePopup",
    (state) => state.common.popup.activePopup,
  );
  const showDetailInfo = USE_SELECTOR(
    "showDetailInfo",
    (state) => state.main.showDetailInfo,
  );
  const productImageLength = USE_SELECTOR(
    "productImageLength",
    (state) => state.product.productImageLength,
  );
  const themeProductInfos = USE_SELECTOR(
    "themeProductInfos",
    (state) => state.home.themeCurationDetailInfoData,
  );
  const hotelInfos = USE_SELECTOR(
    "hotelInfos",
    (state) => state.home.themeCurationHotelDetailData,
  );
  const captionEnable = USE_SELECTOR(
    "captionEnable",
    (state) => state.common.appStatus.captionEnable,
  );
  const fullVideolgCatCd = USE_SELECTOR(
    "fullVideolgCatCd",
    (state) => state.main.fullVideolgCatCd,
  );
  const featuredShowsInfos = USE_SELECTOR(
    "featuredShowsInfos",
    (state) => state.main.featuredShowsInfos,
  );
  const localRecentItems = USE_SELECTOR(
    "localRecentItems",
    (state) => state.localSettings?.recentItems,
  );
  const httpHeader = USE_SELECTOR(
    "httpHeader",
    (state) => state.common?.httpHeader,
  );
  const countryCode = USE_SELECTOR(
    "countryCode",
    (state) => state.common.httpHeader?.cntry_cd,
  );
  const liveChannelInfos = USE_SELECTOR(
    "liveChannelInfos",
    (state) => state.main.liveChannelInfos,
  );
  const showNowInfos = USE_SELECTOR(
    "showNowInfos",
    (state) => state.main.showNowInfo,
  );
  const liveShowInfos = USE_SELECTOR(
    "liveShowInfos",
    (state) => state.main.liveShowInfos,
  );
  const vodSubtitleData = USE_SELECTOR(
    "vodSubtitleData",
    (state) => state.play.subTitleBlobs,
  );
  const broadcast = USE_SELECTOR(
    "broadcast",
    (state) => state.common.broadcast,
  );

  const lastPanelAction = USE_SELECTOR(
    "lastPanelAction",
    (state) => state.panels.lastPanelAction,
  );
  const nowMenu = USE_SELECTOR("nowMenu", (state) => state.common.menu.nowMenu);
  const nowMenuRef = usePrevious(nowMenu);
  const entryMenu = USE_SELECTOR(
    "entryMenu",
    (state) => state.common.menu.entryMenu,
  );
  const [videoLoaded, setVideoLoaded] = USE_STATE("videoLoaded", false);
  const entryMenuRef = usePrevious(entryMenu);
  const panelInfoRef = usePrevious(panelInfo);

  const initialFocusTimeoutJob = useRef(new Job((func) => func(), 100));
  const liveLogParamsRef = useRef(null);
  const vodLogParamsRef = useRef(null);
  const mediaLogParamsRef = useRef(null);
  const prevNowMenuRef = useRef(null);
  const watchInterval = useRef(null);
  // useEffect(() => {
  //   console.log("###videoLoaded", videoLoaded);
  //   if (nowMenu) {
  //   }
  // }, [videoLoaded]);
  const currentLiveShowInfo = useMemo(() => {
    if (liveShowInfos && liveShowInfos.length > 0) {
      const panelInfoChanId = panelInfo?.chanId;
      const isLive = panelInfo?.shptmBanrTpNm === "LIVE";

      if (isLive) {
        const liveShowInfo = liveShowInfos //
          .find(({ chanId }) => panelInfoChanId === chanId);

        return liveShowInfo;
      }

      return {};
    }

    return {};
  }, [liveShowInfos, panelInfo?.chanId, panelInfo?.shptmBanrTpNm]);

  const currentVODShowInfo = useMemo(() => {
    if (showDetailInfo && showDetailInfo.length > 0) {
      const isVOD = panelInfo?.shptmBanrTpNm === "VOD";

      if (isVOD) {
        const vodShowInfo = showDetailInfo[0];

        return vodShowInfo;
      }

      return {};
    }

    return {};
  }, [panelInfo?.shptmBanrTpNm, showDetailInfo]);

  useEffect(() => {
    if (!panelInfo?.modal && panelInfo?.shptmBanrTpNm === "MEDIA") {
      dispatch(sendLogGNB(Config.LOG_MENU.FULL));
      prevNowMenuRef.current = nowMenuRef.current;

      return () => dispatch(sendLogGNB(prevNowMenuRef.current));
    }
  }, [panelInfo?.modal, panelInfo?.shptmBanrTpNm]);

  // creating live log params
  useEffect(() => {
    if (currentLiveShowInfo && Object.keys(currentLiveShowInfo).length > 0) {
      if (currentLiveShowInfo.showId !== panelInfo?.showId) {
        dispatch(
          updatePanel({
            name: panel_names.PLAYER_PANEL,
            panelInfo: {
              chanId: currentLiveShowInfo.chanId,
              modalContainerId: panelInfo?.modalContainerId,
              patnrId: currentLiveShowInfo.patnrId,
              showId: currentLiveShowInfo.showId,
              showUrl: currentLiveShowInfo.showUrl,
            },
          }),
        );

        return;
      }

      let logTemplateNo;

      if (isOnTop && panelInfo?.modal) {
        logTemplateNo = getLogTpNo("LIVE", nowMenu);
        setLogStatus((status) => ({ ...status, isModalLiveLogReady: true }));
      }
      //
      else if (isOnTop && !panelInfo?.modal) {
        logTemplateNo = Config.LOG_TP_NO.LIVE.FULL;
        setLogStatus((status) => ({ ...status, isFullLiveLogReady: true }));
      }
      //
      else if (!isOnTop && !panelInfo?.modal) {
        logTemplateNo = Config.LOG_TP_NO.LIVE.ITEM_DETAIL;
        setLogStatus((status) => ({ ...status, isDetailLiveLogReady: true }));
      }

      liveLogParamsRef.current = {
        entryMenu: entryMenuRef.current,
        lgCatCd: currentLiveShowInfo.catCd ?? "",
        lgCatNm: currentLiveShowInfo.catNm ?? "",
        linkTpCd: panelInfo?.linkTpCd ?? "",
        logTpNo: logTemplateNo,
        nowMenu: nowMenuRef.current,
        patncNm: currentLiveShowInfo.patncNm,
        patnrId: currentLiveShowInfo.patnrId,
        showId: currentLiveShowInfo.showId,
        showNm: currentLiveShowInfo.showNm,
        vdoTpNm: currentLiveShowInfo.vtctpYn
          ? currentLiveShowInfo.vtctpYn === "Y"
            ? "Vertical"
            : "Horizontal"
          : "",
      };
    }
  }, [
    currentLiveShowInfo,
    isOnTop,
    nowMenu,
    panelInfo?.linkTpCd,
    panelInfo?.modal,
    panelInfo?.modalContainerId,
    panelInfo?.showId,
    setLogStatus,
  ]);

  // send live log
  useEffect(() => {
    if (broadcast && Object.keys(broadcast).length === 0) {
      // case: live, modal
      if (
        logStatus.isModalLiveLogReady &&
        isOnTop &&
        panelInfo?.modal &&
        liveLogParamsRef.current?.showId === panelInfo?.showId
      ) {
        let watchStrtDt = formatGMTString(new Date());

        watchInterval.current = setInterval(() => {
          let watchEndDt = formatGMTString(new Date());
          let watchRecord = {
            ...liveLogParamsRef.current,
            watchStrtDt,
            watchEndDt,
          };
          dispatch(changeLocalSettings({ watchRecord }));
        }, 10000);

        return () => {
          setLogStatus((status) => ({
            ...status,
            isModalLiveLogReady: false,
          }));
          clearInterval(watchInterval.current);
          dispatch(
            sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () =>
              dispatch(changeLocalSettings({ watchRecord: {} })),
            ),
          );
        };
      }

      // case: live, full
      if (
        logStatus.isFullLiveLogReady &&
        isOnTop &&
        !panelInfo?.modal &&
        liveLogParamsRef.current?.showId === panelInfo?.showId
      ) {
        let watchStrtDt = formatGMTString(new Date());

        watchInterval.current = setInterval(() => {
          let watchEndDt = formatGMTString(new Date());
          let watchRecord = {
            ...liveLogParamsRef.current,
            watchStrtDt,
            watchEndDt,
          };
          dispatch(changeLocalSettings({ watchRecord }));
        }, 10000);

        return () => {
          setLogStatus((status) => ({
            ...status,
            isFullLiveLogReady: false,
          }));
          clearInterval(watchInterval.current);
          dispatch(
            sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () =>
              dispatch(changeLocalSettings({ watchRecord: {} })),
            ),
          );
        };
      }

      // case: live, item detail
      if (
        logStatus.isDetailLiveLogReady &&
        !isOnTop &&
        !panelInfo?.modal &&
        liveLogParamsRef.current?.showId === panelInfo?.showId
      ) {
        let watchStrtDt = formatGMTString(new Date());

        watchInterval.current = setInterval(() => {
          let watchEndDt = formatGMTString(new Date());
          let watchRecord = {
            ...liveLogParamsRef.current,
            watchStrtDt,
            watchEndDt,
          };
          dispatch(changeLocalSettings({ watchRecord }));
        }, 10000);

        return () => {
          setLogStatus((status) => ({
            ...status,
            isDetailLiveLogReady: false,
          }));
          clearInterval(watchInterval.current);
          dispatch(
            sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () =>
              dispatch(changeLocalSettings({ watchRecord: {} })),
            ),
          );
        };
      }
    }
  }, [
    broadcast,
    isOnTop,
    logStatus.isDetailLiveLogReady,
    logStatus.isFullLiveLogReady,
    logStatus.isModalLiveLogReady,
    panelInfo?.modal,
    panelInfo?.showId,
    setLogStatus,
  ]);

  // creating VOD log params
  useEffect(() => {
    if (
      currentVODShowInfo &&
      Object.keys(currentVODShowInfo).length > 0 &&
      !isVODPaused
    ) {
      let logTemplateNo;

      if (isOnTop && panelInfo?.modal) {
        logTemplateNo = getLogTpNo("VOD", nowMenu);
        setLogStatus((status) => ({ ...status, isModalVodLogReady: true }));
      }
      //
      else if (isOnTop && !panelInfo?.modal) {
        logTemplateNo = Config.LOG_TP_NO.VOD.FULL_VOD;
        setLogStatus((status) => ({ ...status, isFullVodLogReady: true }));
      }
      //
      else if (!isOnTop && !panelInfo?.modal) {
        logTemplateNo = Config.LOG_TP_NO.VOD.ITEM_DETAIL_VOD;
        setLogStatus((status) => ({ ...status, isDetailVodLogReady: true }));
      }

      vodLogParamsRef.current = {
        entryMenu: entryMenuRef.current,
        lgCatCd: currentVODShowInfo?.showCatCd ?? "",
        lgCatNm: currentVODShowInfo?.showCatNm ?? "",
        logTpNo: logTemplateNo,
        linkTpCd: panelInfo?.linkTpCd ?? "",
        nowMenu: nowMenuRef.current,
        patncNm: currentVODShowInfo?.patncNm,
        patnrId: currentVODShowInfo?.patnrId,
        showId: currentVODShowInfo?.showId,
        showNm: currentVODShowInfo?.showNm,
        vdoTpNm: currentVODShowInfo?.vtctpYn
          ? currentVODShowInfo.vtctpYn === "Y"
            ? "Vertical"
            : "Horizontal"
          : "",
      };
    }
  }, [
    currentVODShowInfo,
    isOnTop,
    isVODPaused,
    nowMenu,
    panelInfo?.linkTpCd,
    panelInfo?.modal,
  ]);

  // send VOD log
  useEffect(() => {
    if (broadcast && Object.keys(broadcast).length === 0 && !isVODPaused) {
      // case: VOD, modal
      if (
        logStatus.isModalVodLogReady &&
        isOnTop &&
        panelInfo?.modal &&
        vodLogParamsRef.current?.showId === panelInfo?.showId
      ) {
        let watchStrtDt = formatGMTString(new Date());

        watchInterval.current = setInterval(() => {
          let watchEndDt = formatGMTString(new Date());
          let watchRecord = {
            ...vodLogParamsRef.current,
            watchStrtDt,
            watchEndDt,
          };
          dispatch(changeLocalSettings({ watchRecord }));
        }, 10000);

        return () => {
          setLogStatus((status) => ({
            ...status,
            isModalVodLogReady: false,
          }));
          clearInterval(watchInterval.current);
          dispatch(
            sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () =>
              dispatch(changeLocalSettings({ watchRecord: {} })),
            ),
          );
        };
      }

      // case: VOD, full
      if (
        logStatus.isFullVodLogReady &&
        isOnTop &&
        !panelInfo?.modal &&
        vodLogParamsRef.current?.showId === panelInfo?.showId
      ) {
        let watchStrtDt = formatGMTString(new Date());

        watchInterval.current = setInterval(() => {
          let watchEndDt = formatGMTString(new Date());
          let watchRecord = {
            ...vodLogParamsRef.current,
            watchStrtDt,
            watchEndDt,
          };
          dispatch(changeLocalSettings({ watchRecord }));
        }, 10000);

        return () => {
          setLogStatus((status) => ({
            ...status,
            isFullVodLogReady: false,
          }));
          clearInterval(watchInterval.current);
          dispatch(
            sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () =>
              dispatch(changeLocalSettings({ watchRecord: {} })),
            ),
          );
        };
      }

      // case: VOD, item detail
      if (
        logStatus.isDetailVodLogReady &&
        !isOnTop &&
        !panelInfo?.modal &&
        vodLogParamsRef.current?.showId === panelInfo?.showId
      ) {
        let watchStrtDt = formatGMTString(new Date());

        watchInterval.current = setInterval(() => {
          let watchEndDt = formatGMTString(new Date());
          let watchRecord = {
            ...vodLogParamsRef.current,
            watchStrtDt,
            watchEndDt,
          };
          dispatch(changeLocalSettings({ watchRecord }));
        }, 10000);

        return () => {
          setLogStatus((status) => ({
            ...status,
            isDetailVodLogReady: false,
          }));
          clearInterval(watchInterval.current);
          dispatch(
            sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () =>
              dispatch(changeLocalSettings({ watchRecord: {} })),
            ),
          );
        };
      }
    }
  }, [
    broadcast,
    isOnTop,
    isVODPaused,
    logStatus.isDetailVodLogReady,
    logStatus.isFullVodLogReady,
    logStatus.isModalVodLogReady,
    panelInfo?.modal,
    panelInfo?.showId,
    setLogStatus,
  ]);

  // creating media log params
  useEffect(() => {
    if (panelInfo?.shptmBanrTpNm === "MEDIA" && isOnTop && !isVODPaused) {
      let logTemplateNo;

      if (panelInfo?.modal) {
        logTemplateNo = getLogTpNo("MEDIA", nowMenu);
        setLogStatus((status) => ({ ...status, isModalMediaLogReady: true }));
      }
      //
      else if (!panelInfo?.modal) {
        logTemplateNo = Config.LOG_TP_NO.VOD.FULL_MEDIA;
        setLogStatus((status) => ({ ...status, isFullMediaLogReady: true }));
      }

      mediaLogParamsRef.current = {
        entryMenu: entryMenuRef.current,
        lgCatCd: panelInfo?.lgCatCd ?? "",
        lgCatNm: panelInfo?.lgCatNm ?? "",
        logTpNo: logTemplateNo,
        linkTpCd: panelInfo?.linkTpCd ?? "",
        nowMenu: nowMenuRef.current,
        patncNm: panelInfo?.patncNm ?? "",
        patnrId: panelInfo?.patnrId ?? "",
        showId: panelInfo?.prdtId ?? panelInfo?.showId,
        showNm: panelInfo?.prdtNm ?? panelInfo?.showNm,
        vdoTpNm: "Horizontal",
      };
    }
  }, [
    isOnTop,
    isVODPaused,
    nowMenu,
    panelInfo?.lgCatCd,
    panelInfo?.lgCatNm,
    panelInfo?.linkTpCd,
    panelInfo?.modal,
    panelInfo?.patncNm,
    panelInfo?.patnrId,
    panelInfo?.prdtId,
    panelInfo?.prdtNm,
    panelInfo?.showId,
    panelInfo?.showNm,
    panelInfo?.shptmBanrTpNm,
    setLogStatus,
  ]);

  // send log media
  useEffect(() => {
    if (broadcast && Object.keys(broadcast).length === 0 && !isVODPaused) {
      // case: media, modal
      if (logStatus.isModalMediaLogReady && panelInfo?.modal) {
        let watchStrtDt = formatGMTString(new Date());

        watchInterval.current = setInterval(() => {
          let watchEndDt = formatGMTString(new Date());
          let watchRecord = {
            ...mediaLogParamsRef.current,
            watchStrtDt,
            watchEndDt,
          };
          dispatch(changeLocalSettings({ watchRecord }));
        }, 10000);

        return () => {
          setLogStatus((status) => ({
            ...status,
            isModalMediaLogReady: false,
          }));
          clearInterval(watchInterval.current);
          dispatch(
            sendLogVOD({ ...mediaLogParamsRef.current, watchStrtDt }, () =>
              dispatch(changeLocalSettings({ watchRecord: {} })),
            ),
          );
        };
      }
    }

    // case: media, full
    if (logStatus.isFullMediaLogReady && !panelInfo?.modal) {
      let watchStrtDt = formatGMTString(new Date());

      watchInterval.current = setInterval(() => {
        let watchEndDt = formatGMTString(new Date());
        let watchRecord = {
          ...mediaLogParamsRef.current,
          watchStrtDt,
          watchEndDt,
        };
        dispatch(changeLocalSettings({ watchRecord }));
      }, 10000);

      return () => {
        setLogStatus((status) => ({
          ...status,
          isFullMediaLogReady: false,
        }));
        clearInterval(watchInterval.current);
        dispatch(
          sendLogVOD({ ...mediaLogParamsRef.current, watchStrtDt }, () =>
            dispatch(changeLocalSettings({ watchRecord: {} })),
          ),
        );
      };
    }
  }, [
    broadcast,
    isVODPaused,
    logStatus.isFullMediaLogReady,
    logStatus.isModalMediaLogReady,
    panelInfo?.modal,
    setLogStatus,
  ]);

  const videoVerticalVisible = useMemo(() => {
    if (playListInfo && playListInfo[selectedIndex]?.vtctpYn === "Y") {
      return true;
    }
    return false;
  }, [playListInfo, selectedIndex]);

  const handleItemFocus = useCallback(
    (menu) => {
      dispatch(sendLogGNB(menu));

      if (!videoVerticalVisible) {
        resetTimer(REGULAR_TIMEOUT);
      }
    },
    [resetTimer, videoVerticalVisible],
  );

  const onClickBack = useCallback(
    (ev, isEnd) => {
      //modal로부터 Full 전환된 경우 다시 preview 모드로 돌아감.

      if (
        sideContentsVisible &&
        !videoVerticalVisible &&
        panelInfo.shptmBanrTpNm !== "MEDIA"
      ) {
        setSideContentsVisible(false);
        ev?.stopPropagation();
        // ev?.preventDefault();
        return;
      }

      if (panelInfo.modalContainerId && !panelInfo.modal) {
        dispatch(
          startVideoPlayer({
            ...panelInfo,
            modal: true,
            modalClassName: "",
          }),
        );
        videoPlayer.current?.hideControls();
        setSelectedIndex(backupInitialIndex);
        if (panelInfo.shptmBanrTpNm === "MEDIA") {
          dispatch(
            updatePanel({
              name: panel_names.DETAIL_PANEL,
              panelInfo: {
                launchedFromPlayer: false,
              },
            }),
          );
        }
        ev?.stopPropagation();
        // ev?.preventDefault();
        return;
      }

      if (!panelInfo.modal) {
        dispatch(PanelActions.popPanel());
        dispatch(changeAppStatus({ cursorVisible: false }));

        //딮링크로 플레이어 진입 후 이전버튼 클릭시
        if (panels.length === 1) {
          setTimeout(() => {
            Spotlight.focus(SpotlightIds.HOME_TBODY);
          });
        }
        ev?.stopPropagation();
        // ev?.preventDefault();
        return;
      }
    },
    [
      dispatch,
      panelInfo,
      videoPlayer,
      sideContentsVisible,
      videoVerticalVisible,
      backupInitialIndex,
    ],
  );

  useEffect(() => {
    //todo if(modal)
    return () => {
      // 패널이 2개 존재할때만 popPanel 진행
      if (panelInfo.modal && !isOnTop) {
        dispatch(PanelActions.popPanel());
      } else {
        Spotlight.focus("tbody");
      }
    };
  }, [panelInfo?.modal, isOnTop]);

  useEffect(() => {
    if (showNowInfos && panelInfo.shptmBanrTpNm === "LIVE") {
      const period =
        showNowInfos.period !== undefined ? showNowInfos.period : 30;
      const periodInMilliseconds = period * 1000;

      const timer = setTimeout(() => {
        dispatch(
          getMainLiveShowNowProduct({
            patnrId: panelInfo.patnrId
              ? panelInfo.patnrId
              : playListInfo[selectedIndex].patnrId,
            showId: panelInfo.showId
              ? panelInfo.showId
              : playListInfo[selectedIndex].showId,
            lstChgDt: showNowInfos.lstChgDt,
          }),
        );
      }, periodInMilliseconds);

      return () => {
        clearTimeout(timer);
      };
    }
  }, [showNowInfos, panelInfo]);

  const videoItemFocused = useCallback(() => {
    // 아이템클릭 진입시 포커스
    let hasProperSpot = false;
    let targetId;
    if (!isInitialFocusOccurred) {
      targetId = panelInfo.targetId;

      initialFocusTimeoutJob.current.start(() => {
        const initialFocusTarget = findSelector(
          `[data-spotlight-id="${targetId}"]`,
        );

        if (initialFocusTarget) {
          hasProperSpot = true;
          Spotlight.focus(initialFocusTarget);
          setIsInitialFocusOccurred(true);

          return;
        }
      });
    }
  }, [
    isInitialFocusOccurred,
    panelInfo.targetId,
    panelInfo.modal,
    videoVerticalVisible,
  ]);

  const videoInitialFocused = useCallback(() => {
    if (panelInfo.isUpdatedByClick || !isOnTop) {
      return;
    }
    setContainerLastFocusedElement(null, ["playVideoShopNowBox"]);

    // 세로형모드 포커스
    if (videoVerticalVisible) {
      Spotlight.focus("tab-0");
      return;
    }

    // 화살표버튼 포커스
    const current = Spotlight.getCurrent();
    let hasProperSpot = false;
    if (current) {
      const spotId = current.getAttribute("data-spotlight-id");
      if (spotId && spotId.indexOf("tabChannel-video") >= 0) {
        hasProperSpot = true;
      }
    }

    if (!panelInfo.modal && !videoVerticalVisible && !hasProperSpot) {
      Spotlight.focus(SpotlightIds.PLAYER_TAB_BUTTON);
      return;
    }
    //비디오 진입시 포커스
    if (panelInfo.isIndicatorByClick && shopNowInfo?.length > 0) {
      Spotlight.focus("playVideoShopNowBox");
      return;
    }
  }, [
    shopNowInfo,
    videoVerticalVisible,
    isOnTop,
    panelInfo.modal,
    panelInfo.isUpdatedByClick,
    panelInfo.isIndicatorByClick,

    panelInfo.shptmBanrTpNm,
  ]);

  const cannotPlay = useMemo(() => {
    const topPanel = panels[panels.length - 1];
    return !isOnTop && topPanel?.name === panel_names.PLAYER_PANEL;
  }, [panels, isOnTop]);

  const getPlayer = useCallback((ref) => {
    videoPlayer.current = ref;
  }, []);

  /** for VOD */
  const addPanelInfoToPlayList = useCallback(
    (featuredShowsInfos) => {
      if (Array.isArray(featuredShowsInfos)) {
        const showId = showDetailInfo[0]?.showId;

        const index = featuredShowsInfos.findIndex(
          (show) => show.showId === showId,
        );

        let newArray = [];
        if (index > -1) {
          // 인덱스를 찾은 경우 그대로
          newArray = [...featuredShowsInfos];
          setBackupInitialIndex(index);
          setSelectedIndex(index);
        } else {
          // 인덱스를 찾지 못한 경우 showDetailInfo 를 제일 앞에 배치
          newArray = [{ ...showDetailInfo[0] }, ...featuredShowsInfos];
          setBackupInitialIndex(0);
          setSelectedIndex(0);
        }
        setPlayListInfo(newArray);
      }
    },

    [showDetailInfo],
  );

  useEffect(() => {
    if (panelInfo.shptmBanrTpNm === "LIVE") {
      if (panelInfo.patnrId && panelInfo.showId) {
        dispatch(
          getMainCategoryShowDetail({
            patnrId: panelInfo.patnrId,
            showId: panelInfo.showId,
            curationId: panelInfo.curationId,
          }),
        );
      }
      dispatch(getMainLiveShow({ vodIncFlag: "Y" }));
    }
  }, [
    dispatch,
    panelInfo?.curationId,
    panelInfo?.lgCatCd,
    panelInfo?.patnrId,
    panelInfo?.showId,
    panelInfo?.shptmBanrTpNm,
  ]);

  useEffect(() => {
    if (
      panelInfo.shptmBanrTpNm === "VOD" &&
      showDetailInfo &&
      showDetailInfo.length > 0 &&
      showDetailInfo[0]?.showCatCd &&
      fullVideolgCatCd !== showDetailInfo[0]?.showCatCd //기존에 호출했으면 안한다.
    ) {
      dispatch(
        getHomeFullVideoInfo({
          lgCatCd: showDetailInfo[0].showCatCd,
        }),
      );
    }
    if (
      panelInfo.shptmBanrTpNm === "VOD" &&
      showDetailInfo &&
      showDetailInfo[0] &&
      showDetailInfo[0].showId &&
      showDetailInfo[0].patnrId
    ) {
      if (!featuredShowsInfos || Object.keys(featuredShowsInfos).length === 0) {
        setPlayListInfo(showDetailInfo);
      }
      setShopNowInfo(showDetailInfo[0].productInfos);
      saveToLocalSettings(showDetailInfo[0].showId, showDetailInfo[0].patnrId);
    }
  }, [showDetailInfo]);

  //LIVE
  useEffect(() => {
    if (
      playListInfo &&
      playListInfo.length > 0 &&
      panelInfo.shptmBanrTpNm === "LIVE"
    ) {
      if (playListInfo[selectedIndex]?.patnrId) {
        dispatch(
          getMainLiveShowNowProduct({
            patnrId: playListInfo[selectedIndex]?.patnrId,
            showId: playListInfo[selectedIndex]?.showId,
          }),
        );
      }

      if (playListInfo[selectedIndex]?.catCd) {
        dispatch(
          getHomeFullVideoInfo({
            lgCatCd: playListInfo[selectedIndex]?.catCd,
          }),
        );
      }
    }
  }, [selectedIndex]);

  useEffect(() => {
    if (showDetailInfo && showDetailInfo.length > 0) {
      dispatch(CLEAR_PLAYER_INFO());

      if (
        showDetailInfo[0]?.liveFlag === "N" &&
        showDetailInfo[0]?.chatLogFlag === "Y" &&
        panelInfo.shptmBanrTpNm === "VOD"
      ) {
        dispatch(
          getChatLog({ patnrId: panelInfo.patnrId, showId: panelInfo.showId }),
        );
      }
    }
  }, [showDetailInfo]);

  // videoClick focused
  useEffect(() => {
    if (playListInfo && playListInfo.length > 0) {
      if (panelInfo.targetId) {
        videoItemFocused();
      } else {
        videoInitialFocused();
      }
    }
  }, [playListInfo]);

  //10초 후 닫힐때 TabButton 포커스
  useEffect(() => {
    if (playListInfo && playListInfo.length > 0) {
      videoInitialFocused();
    }
  }, [sideContentsVisible, panelInfo.modal]);

  // liveChannel initial selectedIndex
  useEffect(() => {
    if (panelInfo?.shptmBanrTpNm === "LIVE" && playListInfo?.length > 0) {
      const index = playListInfo.findIndex(
        (item) => item.chanId === panelInfo.chanId,
      );
      if (index !== -1 && !isUpdate) {
        setBackupInitialIndex(index);
        setSelectedIndex(index);
        setIsUpdate(true);
      }
    }
  }, [panelInfo?.shptmBanrTpNm, playListInfo]);

  // live subtitle Luna API
  useEffect(() => {
    if (currentSubtitleBlob) {
      return;
    } else if (isYoutube) {
      if (mediaId) {
        dispatch(requestLiveSubtitle({ mediaId, enable: false }));
        setMediaId(null);
      }
      return;
      //do caption action on VideoPlayer(componentDidUpdate)
    } else {
      if (mediaId && captionEnable && isSubtitleActive && !panelInfo?.modal) {
        dispatch(requestLiveSubtitle({ mediaId, enable: true }));
      } else {
        if (mediaId) {
          dispatch(requestLiveSubtitle({ mediaId, enable: false }));
        }
      }
    }
  }, [
    mediaId,
    isYoutube,
    captionEnable,
    isSubtitleActive,
    currentSubtitleBlob,
    panelInfo.modal,
    panelInfo.shptmBanrTpNm,
  ]);

  // get PlayListInfo
  useEffect(() => {
    if (panelInfo?.shptmBanrTpNm === "VOD") {
      if (showDetailInfo && showDetailInfo.length > 0) {
        if (featuredShowsInfos && featuredShowsInfos.length > 0) {
          addPanelInfoToPlayList(featuredShowsInfos);
        }
      }
    }
  }, [featuredShowsInfos]);

  // get PlayListInfo
  useEffect(() => {
    if (!panelInfo) return;

    switch (panelInfo.shptmBanrTpNm) {
      case "LIVE": {
        const playlist = liveShowInfos ?? liveChannelInfos;

        if (!Array.isArray(playlist)) return;

        const modifiedList = [];

        playlist.forEach((item) => {
          if (item.showType === "vod" && Array.isArray(item.vodInfos)) {
            const mergedVodInfos = item.vodInfos.map((vod) => ({
              ...vod,
              patnrId: item.patnrId,
              patncNm: item.patncNm,
              patncLogoPath: item.patncLogoPath,
              showType: "vod",
            }));

            modifiedList.push(...mergedVodInfos);
          } else {
            modifiedList.push(item);
          }
        });

        setPlayListInfo(modifiedList);

        if (showNowInfos?.prdtChgYn === "N") {
          return;
        }

        if (showNowInfos || showDetailInfo?.length > 0) {
          const productInfos = showNowInfos
            ? showNowInfos.productInfos
            : showDetailInfo[0]?.productInfos;
          setShopNowInfo(productInfos);
        }
        break;
      }
      case "MEDIA":
        setPlayListInfo([panelInfo]);
        break;
      default:
        break;
    }
  }, [
    panelInfo,
    showDetailInfo,
    featuredShowsInfos,
    liveChannelInfos,
    liveShowInfos,
    showNowInfos,
    dispatch,
  ]);

  const liveTotalTime = useMemo(() => {
    let liveTotalTime;
    if (liveShowInfos && panelInfo?.shptmBanrTpNm === "LIVE") {
      const startDtMoment = new Date(liveShowInfos[selectedIndex]?.strtDt);
      const endDtMoment = new Date(liveShowInfos[selectedIndex]?.endDt);

      liveTotalTime = Math.floor((endDtMoment - startDtMoment) / 1000);

      return liveTotalTime;
    }
  }, [liveShowInfos, selectedIndex, panelInfo.shptmBanrTpNm]);

  useEffect(() => {
    const handleVisibilityChange = () => {
      if (
        document.visibilityState === "visible" &&
        liveShowInfos &&
        panelInfo?.shptmBanrTpNm === "LIVE"
      ) {
        const localStartDt = convertUtcToLocal(
          liveShowInfos[selectedIndex]?.strtDt,
        );

        const curDt = new Date();
        const localStartSec = localStartDt?.getTime() / 1000;
        const curSec = curDt?.getTime() / 1000;

        const calculatedLiveTime = curSec - localStartSec;
        if (calculatedLiveTime >= liveTotalTime) {
          setCurrentLiveTimeSeconds(0);
        } else {
          setCurrentLiveTimeSeconds(calculatedLiveTime);
        }
      }
    };

    document.addEventListener("visibilitychange", handleVisibilityChange);

    if (panelInfo.offsetHour) {
      setCurrentLiveTimeSeconds(parseInt(panelInfo.offsetHour));
    } else if (liveShowInfos && panelInfo?.shptmBanrTpNm === "LIVE") {
      const localStartDt = convertUtcToLocal(
        liveShowInfos[selectedIndex]?.strtDt,
      );

      const curDt = new Date();
      const localStartSec = localStartDt?.getTime() / 1000;
      const curSec = curDt?.getTime() / 1000;

      const calculatedLiveTime = curSec - localStartSec;
      if (calculatedLiveTime >= liveTotalTime) {
        setCurrentLiveTimeSeconds(0);
      } else {
        setCurrentLiveTimeSeconds(calculatedLiveTime);
      }
    } else {
      setCurrentLiveTimeSeconds(0);
    }

    return () => {
      document.removeEventListener("visibilitychange", handleVisibilityChange);
    };
  }, [
    liveShowInfos,
    selectedIndex,
    panelInfo.offsetHour,
    panelInfo.shptmBanrTpNm,
    playListInfo,
    liveTotalTime,
  ]);

  useEffect(() => {
    if (panelInfo.shptmBanrTpNm == "LIVE" && liveTotalTime > 0) {
      const interval = setInterval(() => {
        setCurrentLiveTimeSeconds((prev) => {
          if (prev >= liveTotalTime) {
            return 1;
          }
          return prev + 1;
        });
      }, 1000);

      return () => clearInterval(interval);
    }
  }, [liveTotalTime]);

  useEffect(() => {
    if (currentLiveTimeSeconds > liveTotalTime) {
      setTimeout(() => {
        dispatch(getMainLiveShow());
        setShopNowInfo("");
        dispatch(
          getHomeFullVideoInfo({
            lgCatCd: playListInfo[selectedIndex].showCatCd,
          }),
        );
      }, 3000);
    }
  }, [currentLiveTimeSeconds, liveTotalTime]);

  const mediainfoHandler = useCallback(
    (ev) => {
      const type = ev.type;
      if (type !== "timeupdate" && type !== "durationchange") {
        console.log(
          "mediainfoHandler....",
          type,
          ev,
          videoPlayer.current?.getMediaState(),
        );
      }
      if (
        ev === "hlsError" &&
        isNaN(Number(videoPlayer.current?.getMediaState().playbackRate))
      ) {
        dispatch(
          sendBroadCast({
            type: "videoError",
            moreInfo: { reason: "hlsError" },
          }),
        );

        return;
      }

      switch (type) {
        case "timeupdate": {
          setCurrentTime(videoPlayer.current?.getMediaState()?.currentTime);
          break;
        }
        case "error": {
          dispatch(
            sendBroadCast({
              type: "videoError",
              moreInfo: { reason: videoPlayer.current?.getMediaState().error },
            }),
          );
          break;
        }
        case "loadeddata": {
          const mediaId = videoPlayer.current?.video?.media?.mediaId;
          setMediaId(mediaId);
          setVideoLoaded(true);
        }
      }
    },
    [currentLiveTimeSeconds, liveTotalTime],
  );

  useEffect(() => {
    // case: video error when the video is in fullscreen mode
    if (
      broadcast?.type === "videoError" &&
      isOnTop &&
      !panelInfo?.modal &&
      panelInfo?.modalContainerId
    ) {
      // case: Featured Brands
      if (panelInfo?.sourcePanel === panel_names.FEATURED_BRANDS_PANEL) {
        dispatch(PanelActions.popPanel());
      }
    }
  }, [
    broadcast?.type,
    isOnTop,
    panelInfo?.modal,
    panelInfo?.modalContainerId,
    panelInfo?.sourcePanel,
  ]);

  useEffect(() => {
    if (
      panelInfo.modal &&
      panelInfo.modalContainerId &&
      (lastPanelAction === "previewPush" || lastPanelAction === "previewUpdate")
    ) {
      const node = document.querySelector(
        `[data-spotlight-id="${panelInfo.modalContainerId}"]`,
      );
      if (node) {
        const { width, height, top, left } = node.getBoundingClientRect();
        const modalStyle = {
          width: width + "px",
          height: height + "px",
          top: top + "px",
          left: left + "px",
          position: "fixed",
          overflow: "visible",
        };
        setModalStyle(modalStyle);
        let scale = 1;
        if (typeof window === "object") {
          scale = width / window.innerWidth;
          setModalScale(scale);
        }
        dispatch(
          updatePanel({
            name: panel_names.PLAYER_PANEL,
            panelInfo: { modalStyle: modalStyle, modalScale: scale },
          }),
        );
      } else {
        setModalStyle(panelInfo.modalStyle);
        setModalScale(panelInfo.modalScale);
        console.error(
          "PlayerPanel modalContainerId node not found",
          panelInfo.modalContainerId,
        );
      }
    } else if (isOnTop && !panelInfo.modal && videoPlayer.current) {
      if (videoPlayer.current?.getMediaState()?.paused) {
        videoPlayer.current.play();
      }

      if (
        videoPlayer.current.areControlsVisible &&
        !videoPlayer.current.areControlsVisible()
      ) {
        videoPlayer.current.showControls();
      }
    }
  }, [panelInfo, isOnTop]);

  const smallestOffsetHourIndex = useMemo(() => {
    if (shopNowInfo) {
      const filteredVideos = shopNowInfo.filter(
        (video) => video.offsetHour >= currentTime,
      );
      const newSmallestOffsetHour = Math.min(
        ...filteredVideos.map((video) => video.offsetHour),
      );

      const newSmallestOffsetHourIndex = shopNowInfo.findIndex(
        (video) => video.offsetHour === newSmallestOffsetHour.toString(),
      );

      if (shopNowInfo.length === 1) {
        return 0;
      }
      if (newSmallestOffsetHourIndex >= 1) {
        return newSmallestOffsetHourIndex - 1;
      }
      return newSmallestOffsetHourIndex;
    }
  }, [shopNowInfo, currentTime]);

  const currentSubtitleUrl = useMemo(() => {
    if (panelInfo?.shptmBanrTpNm === "MEDIA") {
      return panelInfo.subtitle;
    }
    return playListInfo && playListInfo[selectedIndex]?.showSubtitlUrl;
  }, [playListInfo, selectedIndex, panelInfo]);

  const currentPlayingUrl = useMemo(() => {
    // return "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4";

    if (broadcast.type === "videoError") {
      return null;
    }

    // For previews, always use the direct URL from panelInfo.
    if (panelInfo.modal) {
      return panelInfo.showUrl;
    }

    // For fullscreen, the playlist is the primary source.
    if (
      playListInfo &&
      playListInfo.length > 0 &&
      playListInfo[selectedIndex]?.showUrl
    ) {
      return playListInfo[selectedIndex]?.showUrl;
    }

    // Fallback for fullscreen if playlist isn't ready, use panelInfo URL.
    if (!panelInfo.modal && panelInfo.showUrl) {
      return panelInfo.showUrl;
    }

    return playListInfo && playListInfo[selectedIndex]?.showUrl;
  }, [panelInfo, playListInfo, selectedIndex, broadcast]);

  const isYoutube = useMemo(() => {
    if (currentPlayingUrl && currentPlayingUrl.includes("youtu")) {
      return true;
    } else {
      return false;
    }
  }, [currentPlayingUrl]);

  const currentSubtitleBlob = useMemo(() => {
    if (Config.DEBUG_VIDEO_SUBTITLE_TEST) {
      return dummyVtt;
    }
    return vodSubtitleData[currentSubtitleUrl];
  }, [vodSubtitleData, currentSubtitleUrl]);

  const isReadyToPlay = useMemo(() => {
    if (!currentPlayingUrl) {
      return false;
    }
    if (
      !Config.DEBUG_VIDEO_SUBTITLE_TEST &&
      currentSubtitleUrl &&
      !currentSubtitleBlob
    ) {
      return false;
    }
    return true;
  }, [currentPlayingUrl, currentSubtitleUrl, currentSubtitleBlob, broadcast]);

  const chatVisible = useMemo(() => {
    if (
      playListInfo &&
      chatData &&
      !panelInfo.modal &&
      isOnTop &&
      panelInfo?.shptmBanrTpNm !== "MEDIA"
    ) {
      return true;
    }
    return false;
  }, [playListInfo, chatData, panelInfo.modal, isOnTop]);

  useEffect(() => {
    if (currentSubtitleUrl) {
      dispatch(getSubTitle({ showSubtitleUrl: currentSubtitleUrl }));
    }
  }, [currentSubtitleUrl]);

  useEffect(() => {
    setVideoLoaded(false);
  }, [currentPlayingUrl]);

  const handlePopupClose = useCallback(() => {
    dispatch(setHidePopup());
    setTimeout(() => Spotlight.focus(SpotlightIds.PLAYER_SUBTITLE_BUTTON));
  }, [dispatch]);
  const reactPlayerSubtitleConfig = useMemo(() => {
    if (isSubtitleActive && currentSubtitleBlob) {
      return {
        file: {
          attributes: {
            crossOrigin: "true",
          },
          tracks: [
            { kind: "subtitles", src: currentSubtitleBlob, default: true },
          ],
        },
        youtube: YOUTUBECONFIG,
      };
    } else {
      return {
        youtube: YOUTUBECONFIG,
      };
    }
  }, [currentSubtitleBlob, isSubtitleActive]);

  const currentSideButtonStatus = useMemo(() => {
    if (
      panelInfo?.shptmBanrTpNm !== "MEDIA" &&
      !panelInfo?.modal &&
      sideContentsVisible
    ) {
      return true;
    }
    return false;
  }, [panelInfo, sideContentsVisible]);

  const videoType = useMemo(() => {
    if (currentPlayingUrl) {
      if (currentPlayingUrl.toLowerCase().endsWith(".mp4")) {
        return "video/mp4";
      } else if (currentPlayingUrl.toLowerCase().endsWith(".mpd")) {
        return "application/dash+xml";
      } else if (currentPlayingUrl.toLowerCase().endsWith(".m3u8")) {
        return "application/mpegurl";
      }
    }
    return "application/mpegurl";
  }, [currentPlayingUrl]);

  const orderPhoneNumber = useMemo(() => {
    if (panelInfo?.shptmBanrTpNm !== "MEDIA" && showDetailInfo) {
      return showDetailInfo[0]?.orderPhnNo;
    } else {
      return playListInfo[selectedIndex]?.orderPhnNo;
    }
  }, [panelInfo?.shptmBanrTpNm, showDetailInfo, playListInfo, selectedIndex]);

  const videoThumbnailUrl = useMemo(() => {
    let res = null;

    if (panelInfo.shptmBanrTpNm === "MEDIA") {
      res = panelInfo?.thumbnailUrl;
    } else if (playListInfo && playListInfo.length > 0) {
      res = playListInfo[selectedIndex]?.thumbnailUrl;
    } else if (!res) {
      res = showDetailInfo[0]?.thumbnailUrl;
    }

    return res;
  }, [
    showDetailInfo,
    playListInfo,
    selectedIndex,
    panelInfo.thumbnailUrl,
    panelInfo.shptmBanrTpNm,
  ]);

  const saveToLocalSettings = useCallback(
    (showId, patnrId) => {
      let recentItems = [];
      if (localRecentItems) {
        recentItems = [...localRecentItems];
      }

      const currentDate = new Date();

      const formattedDate = `${
        currentDate.getMonth() + 1
      }/${currentDate.getDate()}`;

      const existingProductIndex = recentItems.findIndex((item) => {
        if (item.showId) return item.showId === showId;
      });

      if (existingProductIndex !== -1) {
        recentItems.splice(existingProductIndex, 1);
      }

      recentItems.push({
        patnrId: patnrId,
        showId: showId,
        date: formattedDate,
        expireTime: currentDate.getTime() + 1000 * 60 * 60 * 24 * 14,
        cntryCd: httpHeader["X-Device-Country"],
      });

      if (recentItems.length >= 51) {
        const data = [...recentItems];
        dispatch(changeLocalSettings({ recentItems: data.slice(1) }));
      } else {
        dispatch(changeLocalSettings({ recentItems }));
      }
    },
    [httpHeader, localRecentItems, dispatch],
  );

  const handleIndicatorDownClick = useCallback(() => {
    if (!initialEnter) {
      setInitialEnter(true);
    }

    let newIndex =
      selectedIndex === playListInfo.length - 1 ? 0 : selectedIndex + 1;
    let initialIndex = newIndex;
    let attempts = 0;

    while (!playListInfo[newIndex]?.showId && attempts < playListInfo.length) {
      newIndex = newIndex === playListInfo.length - 1 ? 0 : newIndex + 1;
      attempts++;
      if (newIndex === initialIndex) break;
    }
    if (playListInfo[newIndex]?.showId) {
      setSelectedIndex(newIndex);
      if (panelInfo.shptmBanrTpNm === "VOD") {
        dispatch(
          getMainCategoryShowDetail({
            patnrId: playListInfo[newIndex]?.patnrId,
            showId: playListInfo[newIndex]?.showId,
            curationId: playListInfo[newIndex]?.curationId,
          }),
        );
        Spotlight.focus("playVideoShopNowBox");
      } else {
        dispatch(
          updatePanel({
            name: panel_names.PLAYER_PANEL,
            panelInfo: {
              chanId: playListInfo[newIndex].chanId,
              patnrId: playListInfo[newIndex].patnrId,
              showId: playListInfo[newIndex].showId,
              shptmBanrTpNm: panelInfo?.shptmBanrTpNm,
              isIndicatorByClick: true,
            },
          }),
        );
      }
    }
    if (!sideContentsVisible) {
      setPrevChannelIndex(selectedIndex);
    }
    setSideContentsVisible(true);
  }, [
    dispatch,
    playListInfo,
    selectedIndex,
    sideContentsVisible,
    initialEnter,
  ]);

  const handleIndicatorUpClick = useCallback(() => {
    if (!initialEnter) {
      setInitialEnter(true);
    }

    let newIndex =
      selectedIndex === 0 ? playListInfo.length - 1 : selectedIndex - 1;
    let initialIndex = newIndex;
    let attempts = 0;

    while (!playListInfo[newIndex]?.showId && attempts < playListInfo.length) {
      newIndex = newIndex === 0 ? playListInfo.length - 1 : newIndex - 1;
      attempts++;
      if (newIndex === initialIndex) break;
    }

    if (playListInfo[newIndex]?.showId) {
      setSelectedIndex(newIndex);
      if (panelInfo.shptmBanrTpNm === "VOD") {
        dispatch(
          getMainCategoryShowDetail({
            patnrId: playListInfo[newIndex]?.patnrId,
            showId: playListInfo[newIndex]?.showId,
            curationId: playListInfo[newIndex]?.curationId,
          }),
        );
        Spotlight.focus("playVideoShopNowBox");
      } else {
        dispatch(
          updatePanel({
            name: panel_names.PLAYER_PANEL,
            panelInfo: {
              chanId: playListInfo[newIndex].chanId,
              patnrId: playListInfo[newIndex].patnrId,
              showId: playListInfo[newIndex].showId,
              shptmBanrTpNm: panelInfo?.shptmBanrTpNm,
              isIndicatorByClick: true,
            },
          }),
        );
      }
    }
    if (!sideContentsVisible) {
      setPrevChannelIndex(selectedIndex);
    }
    setSideContentsVisible(true);
  }, [
    dispatch,
    playListInfo,
    selectedIndex,
    sideContentsVisible,
    initialEnter,
  ]);

  useEffect(() => {
    if (
      panelInfo.shptmBanrTpNm === "VOD" &&
      panelInfo.patnrId &&
      panelInfo.showId
    ) {
      //VOD의 panelInfo.showId 가 변경된 최초 한번만 호출하고, FearchedShow 항목에서 선택시 또는 상하 indicator 선택시 호출한다.
      dispatch(
        getMainCategoryShowDetail({
          patnrId: panelInfo.patnrId,
          showId: panelInfo.showId,
          curationId: panelInfo.curationId,
        }),
      );
    }
  }, [panelInfo.showId]);

  useEffect(() => {
    return () => {
      dispatch(clearShopNowInfo());
      dispatch(CLEAR_PLAYER_INFO());
      setShopNowInfo([]);
    };
  }, []);

  const onEnded = useCallback((e) => {
    if (panelInfoRef.current.shptmBanrTpNm === "MEDIA") {
      dispatch(
        updatePanel({
          name: panel_names.DETAIL_PANEL,
          panelInfo: {
            launchedFromPlayer: true,
            isPlayerFinished: true,
          },
        }),
      );
      Spotlight.pause();
      setTimeout(() => {
        Spotlight.resume();
        dispatch(PanelActions.popPanel());
      }, VIDEO_END_ACTION_DELAY);
      return;
    }
    if (panelInfoRef.current.shptmBanrTpNm === "VOD") {
      Spotlight.pause();
      setTimeout(() => {
        Spotlight.resume();
        if (panelInfoRef.current.modal) {
          videoPlayer.current.play();
        } else {
          dispatch(PanelActions.popPanel(panel_names.PLAYER_PANEL));
        }
      }, VIDEO_END_ACTION_DELAY);
      e?.stopPropagation();
      e?.preventDefault();
      return;
    }
  }, []);

  const onKeyDown = (ev) => {
    if (ev.keyCode === 34) {
      handleIndicatorDownClick();
      ev.stopPropagation();
      ev.preventDefault();
    } else if (ev.keyCode === 33) {
      handleIndicatorUpClick();
      ev.stopPropagation();
      ev.preventDefault();
    }
  };

  const [initialEnter, setInitialEnter] = USE_STATE("initialEnter", true);
  const timerId = useRef(null);
  const showSideContents = useMemo(() => {
    return (
      sideContentsVisible &&
      playListInfo &&
      panelInfo?.shptmBanrTpNm !== "MEDIA" &&
      !panelInfo?.modal &&
      isOnTop
    );
  }, [sideContentsVisible, playListInfo, panelInfo, isOnTop]);

  const qrCurrentItem = useMemo(() => {
    if (shopNowInfo?.length && panelInfo?.shptmBanrTpNm === "LIVE") {
      return shopNowInfo[shopNowInfo.length - 1];
    }

    if (
      shopNowInfo?.length &&
      smallestOffsetHourIndex >= 0 &&
      panelInfo?.shptmBanrTpNm !== "LIVE"
    ) {
      return shopNowInfo[smallestOffsetHourIndex];
    }

    if (panelInfo?.shptmBanrTpNm === "MEDIA" && panelInfo?.qrCurrentItem) {
      return panelInfo.qrCurrentItem;
    }

    return null;
  }, [
    shopNowInfo,
    smallestOffsetHourIndex,
    panelInfo?.shptmBanrTpNm,
    panelInfo?.qrCurrentItem,
  ]);

  const isShowType = useMemo(() => {
    if (["VOD", "MEDIA"].includes(panelInfo.shptmBanrTpNm)) {
      return panelInfo.shptmBanrTpNm;
    }

    const showType = playListInfo?.[selectedIndex]?.showType;
    if (showType === "live") return panelInfo.shptmBanrTpNm;
    if (showType === "vod") return "VOD";

    return panelInfo.shptmBanrTpNm;
  }, [panelInfo.shptmBanrTpNm, playListInfo, selectedIndex]);
  const clearTimer = useCallback(() => {
    clearTimeout(timerId.current);
    timerId.current = null;
  }, []);

  const resetTimer = useCallback((timeout) => {
    if (timerId.current) {
      clearTimer();
    }

    if (initialEnter) {
      setInitialEnter(false);
    }

    timerId.current = setTimeout(() => {
      setSideContentsVisible(false);
    }, timeout);
  }, []);

  useEffect(() => {
    if (isOnTop && !panelInfo.modal && !videoVerticalVisible) {
      setSideContentsVisible(true);
    }
  }, [panelInfo.modal]);

  useEffect(() => {
    const node = document.querySelector(
      `[data-spotlight-id=${TAB_CONTAINER_SPOTLIGHT_ID}]`,
    );

    if (!showSideContents || !node || videoVerticalVisible) return;

    // NOTE 첫 진입 시에는 10초 후 탭이 닫히도록 설정
    if (initialEnter) {
      resetTimer(INITIAL_TIMEOUT);
    }

    const handleEvent = () => resetTimer(REGULAR_TIMEOUT);
    TARGET_EVENTS.forEach((event) => node.addEventListener(event, handleEvent));

    return () => {
      TARGET_EVENTS.forEach((event) =>
        node.removeEventListener(event, handleEvent),
      );

      if (timerId.current) {
        clearTimer();
      }
    };
  }, [showSideContents, videoVerticalVisible]);

  useEffect(() => {
    if (initialEnter || !sideContentsVisible || videoVerticalVisible) return;

    // NOTE button을 통해 탭을 연 경우 5초 후 탭이 닫히도록 설정
    if (sideContentsVisible) {
      resetTimer(REGULAR_TIMEOUT);
    }

    return () => {
      if (timerId.current) {
        clearTimer();
      }
    };
  }, [sideContentsVisible]);

  useLayoutEffect(() => {
    const videoContainer = document.querySelector(`.${css.videoContainer}`);

    if (panelInfo.thumbnail && !videoVerticalVisible) {
      videoContainer.style.background = `url(${panelInfo.thumbnail}) center center / contain no-repeat`;
      videoContainer.style.backgroundColor = "black";
    }

    if (broadcast.type === "videoError" && videoThumbnailUrl) {
      videoContainer.style.background = `url(${videoThumbnailUrl}) center center / contain no-repeat`;
      videoContainer.style.backgroundColor = "black";
    }
  }, [panelInfo.thumbnail, broadcast]);

  const isPlayer = useMemo(() => {
    if (!panelInfo?.modal) {
      return "full player";
    }

    switch (panels[0].name) {
      case "categorypanel":
        return "category";
      case "mypagepanel":
        return "my page";
      case "searchpanel":
        return "search";
      case "hotpickpanel":
        return "hot picks";
      case "featuredbrandspanel":
        return "featured brands";
      case "trendingnowpanel":
        return "trending now";
      case "playerpanel":
        return "home";
    }
  }, [panelInfo.modal, panels]);

  const createLogParams = useCallback(
    (visible) => {
      if (videoLoaded && isShowType) {
        if (showDetailInfo?.[0]) {
          return {
            visible,
            showType: isShowType,
            player: isPlayer,
            category: showDetailInfo[0].showCatNm,
            contentId: showDetailInfo[0].showId,
            contentTitle: showDetailInfo[0].showNm,
            partner: showDetailInfo[0].patncNm,
            contextName: Config.LOG_CONTEXT_NAME.SHOW,
            messageId: Config.LOG_MESSAGE_ID.SHOWVIEW,
          };
        } else if (playListInfo?.[selectedIndex]) {
          const currentItem = playListInfo[selectedIndex];
          return {
            visible,
            showType: isShowType,
            player: isPlayer,
            category: currentItem.catNm,
            contentId: currentItem.showId,
            contentTitle: currentItem.showNm,
            partner: currentItem.patncNm,
            contextName: Config.LOG_CONTEXT_NAME.SHOW,
            messageId: Config.LOG_MESSAGE_ID.SHOWVIEW,
          };
        }
      }
      return null;
    },
    [
      isShowType,
      videoLoaded,
      showDetailInfo?.[0]?.showId,
      playListInfo?.[selectedIndex]?.showId,
    ],
  );

  // isVODPaused 상태 변경 시에만 로그를 보냄
  useEffect(() => {
    if (showDetailInfo?.[0]) {
      const params = createLogParams(!isVODPaused);
      if (params) {
        dispatch(sendLogTotalRecommend(params));
      }
    } else if (playListInfo?.[selectedIndex]) {
      const params = createLogParams(true);
      if (params) {
        dispatch(sendLogTotalRecommend(params));
      }
    }
  }, [isVODPaused, createLogParams]);

  // 컴포넌트 언마운트 시에만 로그를 보냄
  useEffect(() => {
    return () => {
      const params = createLogParams(false);
      if (params) {
        dispatch(sendLogTotalRecommend(params));
      }
    };
  }, [createLogParams, dispatch]);

  useEffect(() => {
    if (playerControl.ownerId === spotlightId && videoPlayer.current) {
      const internalPlayer = videoPlayer.current.getInternalPlayer();
      if (internalPlayer) {
        if (playerControl.isPaused) {
          internalPlayer.pause();
        } else {
          // It only works when it's already paused.
          if (internalPlayer.paused) {
            internalPlayer.play();
          }
        }
      }
    }
  }, [playerControl.isPaused, playerControl.ownerId, spotlightId]);

  /**
   * 최초 포커스 발생시 처리
   */
  useEffect(() => {
    if (panelInfo.isUpdatedByClick && panelInfo.isIndicatorByClick) {
      videoInitialFocused();
    }
  }, [panelInfo.isUpdatedByClick, panelInfo.isIndicatorByClick]);

  return (
    <TPanel
      isTabActivated={false}
      {...props}
      className={classNames(
        css.videoContainer,
        panelInfo.modal && css.modal,
        !isOnTop && css.background,
        !captionEnable && css.hideSubtitle,
      )}
      handleCancel={onClickBack}
      spotlightId={spotlightId}
    >
      <Container
        spotlightRestrict="self-only"
        spotlightId="spotlightId-video-contaienr"
        onKeyDown={onKeyDown}
      >
        {isReadyToPlay && (
          <VideoPlayer
            setApiProvider={getPlayer}
            disabled={panelInfo.modal}
            onEnded={onEnded}
            noAutoPlay={cannotPlay}
            autoCloseTimeout={3000}
            onBackButton={onClickBack}
            spotlightDisabled={
              (!videoVerticalVisible &&
                panelInfo?.shptmBanrTpNm !== "MEDIA" &&
                sideContentsVisible) ||
              panelInfo.modal
            }
            isYoutube={isYoutube}
            src={currentPlayingUrl}
            style={panelInfo.modal ? modalStyle : {}}
            modalScale={panelInfo.modal ? modalScale : 1}
            modalClassName={panelInfo.modal && panelInfo.modalClassName}
            handleIndicatorDownClick={handleIndicatorDownClick}
            handleIndicatorUpClick={handleIndicatorUpClick}
            onError={mediainfoHandler}
            onTimeUpdate={mediainfoHandler}
            onLoadedData={mediainfoHandler}
            onLoadedMetadata={mediainfoHandler}
            onDurationChange={mediainfoHandler}
            reactPlayerConfig={reactPlayerSubtitleConfig}
            thumbnailUrl={videoLoaded ? "" : videoThumbnailUrl}
            videoComponent={
              (typeof window === "object" && !window.PalmSystem) || isYoutube
                ? TReactPlayer
                : Media
            }
            liveTotalTime={liveTotalTime}
            currentLiveTimeSeconds={currentLiveTimeSeconds}
            countryCode={countryCode}
            // VideoOverlay props
            type={isShowType}
            panelInfo={panelInfo}
            captionEnable={captionEnable}
            orderPhnNo={orderPhoneNumber}
            disclaimer={
              shopNowInfo && shopNowInfo[smallestOffsetHourIndex]?.disclaimer
            }
            themeProductInfos={
              themeProductInfos ? themeProductInfos : hotelInfos
            }
            detailThemeProductImageLength={productImageLength}
            playListInfo={playListInfo && playListInfo}
            selectedIndex={selectedIndex}
            qrCurrentItem={qrCurrentItem}
            setIsSubtitleActive={setIsSubtitleActive}
            setSideContentsVisible={setSideContentsVisible}
            sideContentsVisible={sideContentsVisible}
            videoVerticalVisible={videoVerticalVisible}
            setCurrentTime={setCurrentTime}
            setIsVODPaused={setIsVODPaused}
            broadcast={broadcast}
          >
            {typeof window === "object" && window.PalmSystem && (
              <source src={currentPlayingUrl} type={videoType} />
            )}
            {isSubtitleActive &&
              !panelInfo.modal &&
              captionEnable &&
              typeof window === "object" &&
              window.PalmSystem &&
              currentSubtitleBlob && (
                <track kind="subtitles" src={currentSubtitleBlob} default />
              )}
          </VideoPlayer>
        )}

        {chatVisible && (
          <PlayerOverlayChat
            currentTime={currentTime}
            videoVerticalVisible={videoVerticalVisible}
            imageQRCodeUrl={playListInfo[selectedIndex]?.chatQrImgUrl}
            QRCodeUrl={playListInfo[selectedIndex]?.chatUrl}
          />
        )}

        {currentSideButtonStatus && !videoVerticalVisible && playListInfo && (
          <PlayerTabButton
            setSideContentsVisible={setSideContentsVisible}
            sideContentsVisible={sideContentsVisible}
            videoType={isShowType}
          />
        )}

        {showSideContents && (
          <TabContainer
            spotlightId={TAB_CONTAINER_SPOTLIGHT_ID}
            panelInfo={panelInfo}
            shopNowInfo={shopNowInfo}
            playListInfo={playListInfo}
            selectedIndex={selectedIndex}
            setSelectedIndex={setSelectedIndex}
            liveChannelInfos={liveChannelInfos || liveShowInfos}
            videoVerticalVisible={videoVerticalVisible}
            handleItemFocus={handleItemFocus}
            prevChannelIndex={prevChannelIndex}
            currentTime={currentTime}
          />
        )}
      </Container>

      {activePopup === ACTIVE_POPUP.alertPopup && (
        <TPopUp
          kind="textPopup"
          hasText
          hasButton
          text={$L(
            "To view the subtitles, please change the setting to 'On' in the system settings menu.",
          )}
          button2Text={$L("OK")}
          open={popupVisible}
          onClose={handlePopupClose}
        ></TPopUp>
      )}
    </TPanel>
  );
};

const propsAreEqual = (prev, next) => {
  const keys = Object.keys(prev);
  const nextKeys = Object.keys(next);
  // if (!next.isOnTop) {
  //   //ignore event on background
  //   return true;
  // }
  if (keys.length !== nextKeys.length) {
    return false;
  }
  for (let i = 0; i < keys.length; i++) {
    if (prev[keys[i]] !== next[keys[i]]) {
      if (JSON.stringify(prev[keys[i]]) === JSON.stringify(next[keys[i]])) {
        continue;
      }
      return false;
    }
  }
  return true;
};
export default React.memo(PlayerPanelNew, propsAreEqual);
