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 { setContainerLastFocusedElement } from "@enact/spotlight/src/container";

import {
  sendLogCuration,
  sendLogGNB,
  sendLogTotalRecommend,
} from "../../actions/logActions";
import {
  continueGetSubCategory,
  getSubCategory,
} from "../../actions/mainActions";
import { updatePanel } from "../../actions/panelActions";
import SectionTitle from "../../components/SectionTitle/SectionTitle";
import TBody from "../../components/TBody/TBody";
import TButton, { TYPES } from "../../components/TButton/TButton";
import TButtonTab, { LIST_TYPE } from "../../components/TButtonTab/TButtonTab";
import TDropDown from "../../components/TDropDown/TDropDown";
import THeader from "../../components/THeader/THeader";
import TPanel from "../../components/TPanel/TPanel";
import TVerticalPagenator from "../../components/TVerticalPagenator/TVerticalPagenator";
import usePrevious from "../../hooks/usePrevious";
import {
  CATEGORY_DATA_MAX_RESULTS_LIMIT,
  LOG_CONTEXT_NAME,
  LOG_MENU,
  LOG_MESSAGE_ID,
  LOG_TP_NO,
  panel_names,
} from "../../utils/Config";
import {
  $L,
  getSpottableDescendants,
  isElementInContainer,
} from "../../utils/helperMethods";
import { SpotlightIds } from "../../utils/SpotlightIds";
import ItemContents from "./CategoryContents/ItemContents/ItemContents";
import ShowContents from "./CategoryContents/ShowContents/ShowContents";
import css from "./CategoryPanel.module.less";

const Container = SpotlightContainerDecorator({ enterTo: null }, "div");

const TabContainer = SpotlightContainerDecorator(
  { enterTo: "last-focused" },
  "div"
);

const INDEX_ITEM = 0;
const INDEX_SHOWS = 1;
const getButtonTabList = () => {
  return [$L("ITEM"), $L("SHOWS")];
};

let buttonTabList = null;

const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => {
  if (!buttonTabList) {
    buttonTabList = getButtonTabList();
  }

  const dispatch = useDispatch();
  const dataAppendJob = useRef(new Job((func) => func(), 1000));
  const categoryDatas = useSelector((state) => state.main.subCategoryData);
  const categoryParams = useSelector((state) => state.main.categoryParams);
  const categoryFilterCd = useSelector((state) => state.main.categoryFilterCd);
  const topShowInfo = useSelector((state) => state.main.topShowInfo);
  const partnerInfos = useSelector((state) => state.main.partnerInfos);
  const panels = useSelector((state) => state.panels.panels);
  const cbChangePageRef = useRef(null);
  const focusedContainerIdRef = useRef(null);
  const { lgCatCd, lgCatNm, COUNT } = panelInfo;
  const {
    bannerInfos,
    categoryDescInfos,
    categoryItemInfos,
    categoryShowInfos,
    categoryTabTypeCd,
  } = categoryDatas || {};

  const [tab, setTab] = useState(panelInfo.tab ? panelInfo.tab : INDEX_ITEM);
  const tabRef = usePrevious(tab);
  const categoryDatasRef = usePrevious(categoryDatas);
  const [dropDownTab, setDropDownTab] = useState(
    panelInfo.dropDownTab ? panelInfo.dropDownTab : 0
  );
  const dropDownTabRef = usePrevious(dropDownTab);
  const [filterMethods, setFilterMethods] = useState([]);
  const [styleChange, setStyleChange] = useState(false);
  const topPanel = panels[panels.length - 1];
  const [targetId, setTargetId] = useState(null);

  const logParamsRef = useRef(null);
  const timerRef = useRef();

  useEffect(() => {
    if (panelInfo.currentSpot) {
      setTargetId(panelInfo.currentSpot);
    }
  }, [panelInfo]);

  useEffect(() => {
    if (isOnTop) {
      timerRef.current = setTimeout(() => {
        Spotlight.focus(targetId);
      }, 0);
    }
    return () => clearTimeout(timerRef.current);
  }, [targetId]);

  useEffect(() => {
    let nowMenu = null;
    if (tab === INDEX_ITEM) {
      if (categoryItemInfos) {
        nowMenu =
          categoryItemInfos?.subCatItemList.length === 0
            ? LOG_MENU.CATEGORY_BEST_SELLER
            : LOG_MENU.CATEGORY_ITEM;
      }
    } else if (tab === INDEX_SHOWS) {
      if (categoryShowInfos) {
        nowMenu =
          categoryShowInfos?.subCatShowList.length === 0
            ? LOG_MENU.CATEGORY_POPULAR_SHOWS
            : LOG_MENU.CATEGORY_SHOWS;
      }
    }

    if (nowMenu) {
      dispatch(sendLogGNB(nowMenu));
    }

    logParamsRef.current = {
      cnttTpNm: "",
      expsOrd: `${panelInfo?.expsOrd}`,
      lgCatCd,
      lgCatNm,
      linkTpCd: panelInfo?.linkTpCd,
      logTpNo: LOG_TP_NO.CURATION.CATEGORY,
      sortTpNm: "",
    };
  }, [categoryItemInfos, categoryShowInfos, panelInfo?.expsOrd, tab]);

  useEffect(() => {
    const timer = setTimeout(() => {
      const cnttTpNm = tab === INDEX_SHOWS ? "Show" : "Item";
      dispatch(sendLogCuration({ ...logParamsRef.current, cnttTpNm }));
    }, 1000);

    return () => clearTimeout(timer);
  }, [panelInfo?.expsOrd, tab]);

  useEffect(() => {
    const timer = setTimeout(() => {
      const sortTpNm = dropDownTab === 0 ? "New" : "Popular";
      dispatch(sendLogCuration({ ...logParamsRef.current, sortTpNm }));
    }, 1000);

    return () => clearTimeout(timer);
  }, [dropDownTab, panelInfo?.expsOrd]);

  const reload = useCallback(() => {
    const tabType = tabRef.current === INDEX_SHOWS ? "CAT00101" : "CAT00102";
    const filterType = dropDownTabRef.current === 0 ? "CAT00202" : "CAT00201";
    const pageSize = "20";

    if (
      categoryParams?.lgCatCd !== lgCatCd ||
      categoryParams?.tabType !== tabType ||
      categoryParams?.filterType !== filterType ||
      categoryParams?.pageSize !== pageSize
    ) {
      dispatch(
        getSubCategory(
          {
            lgCatCd,
            pageSize: pageSize,
            tabType: tabType,
            filterType: filterType,
          },
          1,
          null,
          true
        )
      );
    }
  }, [categoryParams, lgCatCd, tab, dropDownTab]);

  //panelInfo changed
  useEffect(() => {
    if (isOnTop) {
      if (panelInfo.dropDownTab !== dropDownTab) {
        setDropDownTab(panelInfo.dropDownTab ? panelInfo.dropDownTab : 0);
      }
      if (panelInfo.tab !== tab) {
        setContainerLastFocusedElement(null, [SpotlightIds.SHOW_PRODUCTS_BOX]);
        setContainerLastFocusedElement(null, [SpotlightIds.SHOW_CONTENTS_BOX]);
        setContainerLastFocusedElement(null, [
          SpotlightIds.CATEGORY_CONTENTS_BOX,
        ]);
        setTab(panelInfo.tab ? panelInfo.tab : INDEX_ITEM);
      } else if (panelInfo.currentSpot) {
        Spotlight.focus(panelInfo.currentSpot);
      }

      setTimeout(() => {
        if (tab === INDEX_ITEM) {
          Spotlight.focus(`[data-spotlight-id="${"tab-" + tab}"]`);
        }
        Spotlight.focus(SpotlightIds.TBODY);
        if (panelInfo.currentSpot) {
          Spotlight.focus(panelInfo.currentSpot);
        }
        reload();
      }, 100);
    }
  }, [panelInfo, isOnTop]);

  useEffect(() => {
    if (categoryDatas) {
      const tabNode = document.querySelector(
        `[data-spotlight-id="${"tab-" + tab}"]`
      );
      if (tabNode) {
        setContainerLastFocusedElement(tabNode, [
          SpotlightIds.CATEGORY_TAB_CONTAINER,
        ]);
      }
    }
  }, [tab, categoryDatas, panelInfo]);

  useEffect(() => {
    setContainerLastFocusedElement(null, [SpotlightIds.SHOW_PRODUCTS_BOX]);
    setContainerLastFocusedElement(null, [SpotlightIds.SHOW_CONTENTS_BOX]);
    setContainerLastFocusedElement(null, [SpotlightIds.CATEGORY_CONTENTS_BOX]);
    reload();
    if (categoryFilterCd) {
      const detailCdNmValues = categoryFilterCd
        .map((item) => $L(item.detailCdNm))
        .reverse();

      setFilterMethods(detailCdNmValues);
    }
  }, [dropDownTab, tab, categoryFilterCd]);

  const handleButtonTabClick = useCallback(
    ({ index }) => {
      if (index === tab) {
        return;
      }

      setTab(index);
      if (cbChangePageRef.current) {
        cbChangePageRef.current(0, false, false);
      }
    },
    [tab]
  );

  const handleItemClick = useCallback(
    (ev) => {
      const target = ev.currentTarget;
      let currentSpotId = null;
      if (target) {
        currentSpotId = target.getAttribute("data-spotlight-id");
      }
      dispatch(
        updatePanel({
          name: panel_names.CATEGORY_PANEL,
          panelInfo: {
            currentSpot: currentSpotId,
            tab: tabRef.current,
            dropDownTab: dropDownTabRef.current,
            focusedContainerId: focusedContainerIdRef.current,
          },
        })
      );

      let clickedItem = null;
      let clickedShow = null;
      let clickedTopShow = null;
      let clickedTopShowPrd = null;

      if (
        categoryItemInfos?.subCatItemList &&
        currentSpotId.includes("categoryItemContents")
      ) {
        const clickedNumber = Number(
          currentSpotId.replace("categoryItemContents", "")
        );
        clickedItem = categoryItemInfos.subCatItemList[clickedNumber];
      }

      if (
        categoryShowInfos?.subCatShowList &&
        currentSpotId.includes("categoryShowContents")
      ) {
        const clickedNumber = Number(
          currentSpotId.replace("categoryShowContents", "")
        );
        clickedShow = categoryShowInfos.subCatShowList[clickedNumber];
      }

      if (topShowInfo?.productInfos) {
        if (currentSpotId.includes("showCategory-spotlightId")) {
          const clickedId = currentSpotId.replace(
            "showCategory-spotlightId-",
            ""
          );
          clickedTopShowPrd = topShowInfo.productInfos.find(
            (item) => clickedId === item.prdtId
          );
        } else if (currentSpotId.includes("category-topshow")) {
          clickedTopShow = topShowInfo;
        }
      }

      const params = {
        tabTitle: tabRef.current === 0 ? "ITEM" : "SHOWS",
        sortType: dropDownTabRef.current === 0 ? "NEW" : "MOST POPULAR",
        contextName: LOG_CONTEXT_NAME.CATEGORY,
        messageId: LOG_MESSAGE_ID.CONTENTCLICK,
      };

      // 파트너 이름 찾기 함수
      const findPartnerName = (patnrId) => {
        const partner = partnerInfos?.find((item) => item.patnrId === patnrId);
        return partner?.patncNm || null;
      };

      const sendLog = (newParams) => {
        dispatch(sendLogTotalRecommend(newParams));
      };

      // 탑쇼 로그
      if (clickedTopShow) {
        const { showId, showNm, patnrId } = clickedTopShow;
        sendLog({
          ...params,
          category: categoryShowInfos?.catNm,
          partner: findPartnerName(patnrId),
          showId: showId,
          showTitle: showNm,
        });
      }

      // 탑쇼 상품 로그
      if (clickedTopShowPrd) {
        const { prdtId, prdtNm, priceInfo } = clickedTopShowPrd;
        const [regularPrice, discountPrice, , , discountRate] =
          priceInfo?.split("|") || [];
        sendLog({
          ...params,
          category: categoryShowInfos?.catNm,
          partner: findPartnerName(topShowInfo?.patnrId),
          showId: prdtId,
          showTitle: prdtNm,
          price: discountRate ? discountPrice : regularPrice,
          discount: discountRate,
        });
      }

      // 쇼 로그
      if (clickedShow) {
        const { showId, showNm, patnrId } = clickedShow;
        sendLog({
          ...params,
          category: categoryShowInfos?.catNm,
          partner: findPartnerName(patnrId),
          showId: showId,
          showTitle: showNm,
        });
      }

      // 아이템 로그
      if (clickedItem) {
        const { prdtNm, priceInfo, brndNm, prdtId, patnrId } = clickedItem;
        const [regularPrice, discountPrice, , , discountRate] =
          priceInfo?.split("|") || [];
        sendLog({
          ...params,
          category: categoryItemInfos?.catNm,
          partner: findPartnerName(patnrId),
          productId: prdtId,
          productTitle: prdtNm,
          price: discountRate ? discountPrice : regularPrice,
          discount: discountRate,
          brand: brndNm,
        });
      }
    },
    [tab, categoryItemInfos, categoryShowInfos, topShowInfo]
  );

  const handleSelectFilter = useCallback(
    ({ selected }) => {
      if (selected === dropDownTab) {
        return;
      }

      setDropDownTab(selected);
    },
    [dropDownTab]
  );

  const handleStyle = useCallback(() => {
    setStyleChange(true);
  }, []);

  const handleStyleOut = useCallback(() => {
    setStyleChange(false);
  }, []);

  const handleTopButtonClick = useCallback(() => {
    if (cbChangePageRef.current) {
      cbChangePageRef.current(0, true, false);
    }
    setContainerLastFocusedElement(null, [SpotlightIds.CATEGORY_CONTENTS_BOX]);
    Spotlight.focus("tab-" + tab);
  }, [tab]);

  //onScroll* event can't use Callback
  const onScrollStop = useCallback((ev) => {
    const targetContentsBoxId =
      tabRef.current === INDEX_SHOWS
        ? SpotlightIds.SHOW_CONTENTS_BOX
        : SpotlightIds.CATEGORY_CONTENTS_BOX;
    const targetKey =
      tabRef.current === INDEX_SHOWS
        ? "categoryShowInfos"
        : "categoryItemInfos";
    const targetData = categoryDatasRef.current[targetKey];
    const subKey = targetData?.subCatItemList
      ? "subCatItemList"
      : "subCatShowList";
    const spottableDescendants = getSpottableDescendants(targetContentsBoxId);

    const visibleIndexes = [];
    spottableDescendants.forEach((child, index) => {
      if (isElementInContainer(child)) {
        visibleIndexes.push(index);
      }
    });
    if (visibleIndexes.length > 0) {
      const lastVisibleIndex = visibleIndexes[visibleIndexes.length - 1];
      const nextQueryIndex =
        (Math.floor(lastVisibleIndex / CATEGORY_DATA_MAX_RESULTS_LIMIT) + 1) *
        CATEGORY_DATA_MAX_RESULTS_LIMIT;

      if (targetData && !targetData[subKey][nextQueryIndex]) {
        dataAppendJob.current.throttle(() => {
          dispatch(
            continueGetSubCategory(
              targetKey,
              Math.floor(nextQueryIndex / CATEGORY_DATA_MAX_RESULTS_LIMIT) + 1
            )
          );
        });
      }
    }
  }, []);

  const showGotoTopButton = useMemo(() => {
    const targetData =
      tab === INDEX_SHOWS ? categoryShowInfos : categoryItemInfos;
    const subKey = targetData?.subCatItemList
      ? "subCatItemList"
      : "subCatShowList";

    if (!targetData || !targetData[subKey] || targetData.total < 5) {
      return false;
    }
    return subKey === "subCatShowList"
      ? targetData[subKey].length + 1 >= targetData.total
      : targetData[subKey].length >= targetData.total;
  }, [tab, categoryShowInfos, categoryItemInfos]);

  const itemCountNumbers = useMemo(() => {
    if (categoryItemInfos && tab === INDEX_ITEM) {
      return categoryItemInfos.subCatItemList.length > 0
        ? categoryItemInfos.total
        : "0";
    } else if (categoryShowInfos && tab === INDEX_SHOWS) {
      return categoryShowInfos.subCatShowList.length > 0
        ? categoryShowInfos.total
        : "0";
    } else {
      return;
    }
  }, [categoryItemInfos, categoryShowInfos, tab]);

  useEffect(() => {
    const c = document.getElementById("floatLayer");

    c.classList.add("category_dropdown");
    return () => {
      c.classList.remove("category_dropdown");
    };
  }, []);

  const onFocusedContainerId = useCallback((containerId) => {
    focusedContainerIdRef.current = containerId;
  }, []);

  return (
    <TPanel spotlightId={spotlightId}>
      <THeader title="CATEGORY" ariaLabel="CATEGORY, HEADING 1" />
      {categoryDatas && (
        <TBody className={css.tBody} scrollable={false}>
          <TVerticalPagenator
            className={css.tVerticalPagenator}
            spotlightId={"category_verticalPagenator"}
            defaultContainerId={panelInfo?.focusedContainerId}
            onScrollStop={onScrollStop}
            onFocusedContainerId={onFocusedContainerId}
            cbChangePageRef={cbChangePageRef}
            topMargin={15}
            deleteFocus={true}
          >
            <Container
              spotlightId={"categorypanel_top_point_area"}
              data-wheel-point={true}
              className={css.cateContainer}
            >
              {panelInfo && categoryDatas && (
                <SectionTitle
                  title={lgCatNm}
                  className={css.title}
                  itemCount={itemCountNumbers}
                  ariaLabel={lgCatNm}
                />
              )}
              {topPanel &&
                topPanel.name === panel_names.CATEGORY_PANEL &&
                buttonTabList &&
                buttonTabList.length > 0 && (
                  <TabContainer className={css.tabContainer}>
                    <TButtonTab
                      contents={buttonTabList}
                      onItemClick={handleButtonTabClick}
                      selectedIndex={tab}
                      listType={LIST_TYPE.medium}
                      spotlightId={SpotlightIds.CATEGORY_TAB_CONTAINER}
                    />
                    <TDropDown
                      className={classNames(
                        css.dropdown,
                        styleChange === true ? css.categoryDropdown : null
                      )}
                      onSelect={handleSelectFilter}
                      onOpen={handleStyle}
                      onClose={handleStyleOut}
                      selectedIndex={dropDownTab}
                      width="small"
                    >
                      {filterMethods}
                    </TDropDown>
                  </TabContainer>
                )}
              {tab === INDEX_ITEM && <ItemContents onClick={handleItemClick} />}
              {tab === INDEX_SHOWS && (
                <ShowContents onClick={handleItemClick} />
              )}
            </Container>
            {showGotoTopButton && (
              <TButton
                type={TYPES.topButton}
                size={null}
                data-wheel-point={true}
                onClick={handleTopButtonClick}
                ariaLabel="Move to Top, Button"
              />
            )}
          </TVerticalPagenator>
        </TBody>
      )}
    </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]]) {
      return false;
    }
  }
  return true;
};
export default React.memo(CategoryPanel, propsAreEqual);
