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

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

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

import { sendLogCuration, sendLogGNB } from "../../actions/logActions";
import { updatePanel } from "../../actions/panelActions";
import CustomImage from "../../components/CustomImage/CustomImage";
import TPanel from "../../components/TPanel/TPanel";
import { LOG_TP_NO, panel_names } from "../../utils/Config";
import ImageOverlayContents from "./ImageOverlayContents/ImageOverlayContents";
import css from "./ImagePanel.module.less";
import ImageSideContents from "./ImageSideContents/ImageSideContents";

const Container = SpotlightContainerDecorator(
  { enterTo: "last-focused" },
  "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 ImagePanel = ({ panelInfo, spotlightId }) => {
  const dispatch = useDispatch();

  const brandShowroomInfo = useSelector(
    (state) => state.brand.brandShowroomData.data.brandShowroomInfo
  );

  const [isInitialFocusOccurred, setIsInitialFocusOccurred] = useState(false);
  const [otherRoomThemeInfos, setOtherRoomThemeInfos] = useState(null);
  const [overlayContentsVisible, setOverlayContentsVisible] = useState(true);
  const [selectedRoomThemeInfo, setSelectedRoomThemeInfo] = useState(null);
  const [selectedRoomThemeInfosLength, setSelectedRoomThemeInfosLength] =
    useState(null);
  const [selectedThemeExpsOrd, setSelectedThemeExpsOrd] = useState(null);
  const [sideContentsVisible, setSideContentsVisible] = useState(true);

  const initialFocusTimeoutJob = useRef(new Job((func) => func(), 0));
  const themeDisplayTimerRef = useRef(null);

  const memoizedRoomThemeInfo = useMemo(
    () =>
      brandShowroomInfo?.find(({ roomId }) => roomId === panelInfo?.roomId) ||
      null,
    [brandShowroomInfo, panelInfo?.roomId]
  );

  useEffect(() => {
    let sideContentsTimer;
    const handleAction = () => clearTimeout(sideContentsTimer);

    window.addEventListener("click", handleAction);
    window.addEventListener("keydown", handleAction);

    sideContentsTimer = setTimeout(() => setSideContentsVisible(false), 10000);

    return () => {
      window.removeEventListener("click", handleAction);
      window.removeEventListener("keydown", handleAction);

      clearTimeout(sideContentsTimer);
    };
  }, []);

  useEffect(() => {
    let overlayContentsTimer;
    const handleAction = () => clearTimeout(overlayContentsTimer);

    if (!sideContentsVisible) {
      window.addEventListener("click", handleAction);
      window.addEventListener("keydown", handleAction);

      overlayContentsTimer = setTimeout(
        () => setOverlayContentsVisible(false),
        3000
      );
    }

    return () => {
      window.removeEventListener("click", handleAction);
      window.removeEventListener("keydown", handleAction);

      clearTimeout(overlayContentsTimer);
    };
  }, [sideContentsVisible]);

  // effect: set selectedThemeExpsOrd on initial render
  useEffect(() => {
    if (panelInfo?.themeExpsOrd) {
      setSelectedThemeExpsOrd(panelInfo?.themeExpsOrd);
    }
  }, []);

  // effect: set selectedRoomThemeInfo and otherRoomThemeInfos based on selectedThemeExpsOrd
  useEffect(() => {
    if (memoizedRoomThemeInfo && selectedThemeExpsOrd) {
      const { roomThemeInfos } = memoizedRoomThemeInfo;

      if (roomThemeInfos) {
        setSelectedRoomThemeInfosLength(roomThemeInfos.length);
        setSelectedRoomThemeInfo(
          roomThemeInfos.find(
            ({ themeExpsOrd }) => themeExpsOrd === selectedThemeExpsOrd
          )
        );
        setOtherRoomThemeInfos(
          roomThemeInfos.filter(
            ({ themeExpsOrd }) => themeExpsOrd !== selectedThemeExpsOrd
          )
        );
      }
    }
  }, [memoizedRoomThemeInfo, selectedThemeExpsOrd]);

  // effect: curation log
  useEffect(() => {
    if (panelInfo && selectedRoomThemeInfo) {
      const { linkTpCd = "", patncNm, patnrId } = panelInfo;
      const params = {
        curationId: selectedRoomThemeInfo?.themeId,
        curationNm: selectedRoomThemeInfo?.themeNm,
        expsOrd: `${selectedRoomThemeInfo?.themeExpsOrd}`,
        logTpNo: LOG_TP_NO.CURATION.SHOWROOM,
        linkTpCd,
        patncNm,
        patnrId,
      };

      themeDisplayTimerRef.current = setTimeout(
        () => dispatch(sendLogCuration(params)),
        3000
      );

      return () => clearTimeout(themeDisplayTimerRef.current);
    }
  }, [selectedRoomThemeInfo]);

  // effect: focus logic
  useEffect(() => {
    if (!isInitialFocusOccurred) {
      const targetId =
        panelInfo?.lastFocusedTargetId ??
        panelInfo?.targetId ??
        "spotlightId-arrow";

      initialFocusTimeoutJob.current.start(() => {
        const focusTarget = findSelector(`[data-spotlight-id="${targetId}"]`);
        if (focusTarget) Spotlight.focus(focusTarget);

        setIsInitialFocusOccurred(true);
      });
    }
  }, [isInitialFocusOccurred]);

  // effect: unmount
  useEffect(() => {
    return () => {
      const lastFocusedTargetId = getContainerId(Spotlight.getCurrent());

      if (lastFocusedTargetId) {
        dispatch(
          updatePanel({
            name: panel_names.IMAGE_PANEL,
            panelInfo: {
              lastFocusedTargetId,
            },
          })
        );
      }
    };
  }, []);

  const handleClick = useCallback(
    (e) => {
      if (sideContentsVisible) {
        if (e.target.id === "dark-gradient") {
          setSideContentsVisible(false);
        }
      } else setOverlayContentsVisible((prev) => !prev);
    },
    [sideContentsVisible]
  );

  const handleSelectedTab = useCallback(
    (nowMenu) => dispatch(sendLogGNB(nowMenu)),
    []
  );

  return (
    <TPanel
      className={css.tPanel}
      isTabActivated={false}
      spotlightId={spotlightId}
    >
      {selectedRoomThemeInfo &&
        selectedRoomThemeInfosLength &&
        selectedThemeExpsOrd && (
          <Container
            className={classNames(
              css.container,
              sideContentsVisible && css.darkOverlay
            )}
            onClick={handleClick}
          >
            <figure>
              <CustomImage src={selectedRoomThemeInfo.themeImgUrl} alt="" />
            </figure>

            <ImageOverlayContents
              overlayContentsVisible={overlayContentsVisible}
              panelInfo={panelInfo}
              selectedRoomThemeInfosLength={selectedRoomThemeInfosLength}
              selectedThemeExpsOrd={selectedThemeExpsOrd}
              setOverlayContentsVisible={setOverlayContentsVisible}
              setSelectedThemeExpsOrd={setSelectedThemeExpsOrd}
              setSideContentsVisible={setSideContentsVisible}
              sideContentsVisible={sideContentsVisible}
              themeNm={selectedRoomThemeInfo.themeNm}
            />

            {sideContentsVisible && (
              <ImageSideContents
                otherRoomThemeInfos={otherRoomThemeInfos}
                handleSelectedTab={handleSelectedTab}
                selectedRoomThemeInfo={selectedRoomThemeInfo}
                setSelectedThemeExpsOrd={setSelectedThemeExpsOrd}
              />
            )}
          </Container>
        )}
    </TPanel>
  );
};

export default ImagePanel;
