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

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 { sendLogGNB, sendLogTotalRecommend } from "../../actions/logActions";
import { getMyRecommandedKeyword } from "../../actions/myPageActions";
import { popPanel, updatePanel } from "../../actions/panelActions";
import { getSearch, resetSearch } from "../../actions/searchActions";
import TBody from "../../components/TBody/TBody";
import TInput, { ICONS, KINDS } from "../../components/TInput/TInput";
import TPanel from "../../components/TPanel/TPanel";
import TVerticalPagenator from "../../components/TVerticalPagenator/TVerticalPagenator";
import usePrevious from "../../hooks/usePrevious";
import {
  LOG_CONTEXT_NAME,
  LOG_MENU,
  LOG_MESSAGE_ID,
  panel_names,
} from "../../utils/Config";
import { SpotlightIds } from "../../utils/SpotlightIds";
import NoSearchResults from "./NoSearchResults/NoSearchResults";
import RecommendedKeywords from "./RecommendedKeywords/RecommendedKeywords";
import css from "./SearchPanel.module.less";
import SearchResults from "./SearchResults/SearchResults";

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

export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
  const dispatch = useDispatch();
  const loadingComplete = useSelector((state) => state.common?.loadingComplete);
  const recommandedKeywords = useSelector(
    (state) => state.myPage.recommandedKeywordData.data?.keywords
  );
  const { searchDatas: searchDatas } = useSelector((state) => state.search);
  const searchPerformed = useSelector((state) => state.search.searchPerformed);
  const panels = useSelector((state) => state.panels.panels);

  const [firstSpot, setFirstSpot] = useState(false);
  const [currentPage, setCurrentPage] = useState(1);
  const [paginatedKeywords, setPaginatedKeywords] = useState([]);
  const [pageChanged, setPageChanged] = useState(false);
  const [searchQuery, setSearchQuery] = useState(
    panelInfo.searchVal ? panelInfo.searchVal : null
  );
  const [position, setPosition] = useState(null);

  let searchQueryRef = usePrevious(searchQuery);
  let isOnTopRef = usePrevious(isOnTop);

  const isRecommendedSearchRef = useRef(false);

  const firstButtonSpotlightId = "first-keyword-button";
  const focusJob = useRef(new Job((func) => func(), 100));
  const cbChangePageRef = useRef(null);
  const [focusedContainerId, setFocusedContainerId] = useState(
    panelInfo?.focusedContainerId
  );
  const focusedContainerIdRef = usePrevious(focusedContainerId);
  const bestSellerDatas = useSelector(
    (state) => state.product.bestSellerData.bestSeller
  );

  useEffect(() => {
    if (loadingComplete && !recommandedKeywords) {
      dispatch(getMyRecommandedKeyword());
    }
  }, [loadingComplete]);

  useEffect(() => {
    if (isOnTop) {
      let menu;
      if (!searchPerformed) menu = LOG_MENU.SEARCH_SEARCH;
      else {
        if (searchQueryRef.current)
          menu =
            Object.keys(searchDatas).length > 0
              ? LOG_MENU.SEARCH_RESULT
              : LOG_MENU.SEARCH_BEST_SELLER;
      }
      dispatch(sendLogGNB(menu));
    }
  }, [isOnTop, searchDatas, searchPerformed]);

  useEffect(() => {
    if (!searchQuery) {
      dispatch(resetSearch());
    }
  }, [dispatch]);

  useEffect(() => {
    if (recommandedKeywords) {
      const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
      const endIndex = startIndex + ITEMS_PER_PAGE;

      setPaginatedKeywords(recommandedKeywords.slice(startIndex, endIndex));
    }
  }, [recommandedKeywords, currentPage]);

  useEffect(() => {
    if (pageChanged && paginatedKeywords.length > 0) {
      Spotlight.focus(firstButtonSpotlightId);

      setPageChanged(false);
    }
  }, [pageChanged, paginatedKeywords]);

  const handleSearchChange = useCallback((e) => {
    const query = e.value;

    if (query.length <= 255) {
      setSearchQuery(query);
    }
  }, []);

  useEffect(() => {
    const result = Object.values(searchDatas).reduce((acc, curr) => {
      return acc + curr.length;
    }, 0);

    if (searchQuery) {
      dispatch(
        sendLogTotalRecommend({
          query: searchQuery,
          searchType: searchPerformed ? "query" : "keyword",
          result: result,
          contextName: LOG_CONTEXT_NAME.SEARCH,
          messageId: LOG_MESSAGE_ID.SEARCH_ITEM,
        })
      );
    }
  }, [searchDatas, searchPerformed, dispatch, handleSearchSubmit]);

  const handleSearchSubmit = useCallback(
    (query) => {
      if (!searchPerformed && !query) return;
      if (query.trim()) {
        dispatch(
          getSearch({
            service: "com.lgshop.app",
            query: query,
            domain: "theme,show,item",
          })
        );
      } else {
        dispatch(resetSearch());
      }
      setSearchQuery(query);
    },
    [dispatch, searchPerformed, searchDatas, searchQuery]
  );

  const handleNext = useCallback(() => {
    if (!isOnTopRef.current) {
      return;
    }
    setCurrentPage((prev) => prev + 1);
    setPageChanged(true);
  }, [currentPage]);

  const handlePrev = useCallback(() => {
    if (!isOnTopRef.current) {
      return;
    }
    setCurrentPage((prev) => (prev > 1 ? prev - 1 : prev));
    setPageChanged(true);
  }, [currentPage]);

  const hasPrevPage = currentPage > 1;
  const hasNextPage =
    currentPage * ITEMS_PER_PAGE < recommandedKeywords?.length;

  useEffect(() => {
    if (panelInfo && isOnTop) {
      if (panelInfo.currentSpot && firstSpot) {
        Spotlight.focus(panel_names.SEARCH_PANEL);
      }
    }
  }, [panelInfo, isOnTop]);

  useEffect(() => {
    return () => {
      dispatch(
        updatePanel({
          name: panel_names.SEARCH_PANEL,
          panelInfo: {
            searchVal: searchQueryRef.current,
            focusedContainerId: focusedContainerIdRef.current,
          },
        })
      );
    };
  }, []);

  const handleKeydown = (e) => {
    if (!isOnTopRef.current) {
      return;
    }

    if (e.key === "Enter") {
      handleSearchSubmit(searchQuery);
    }

    if (position === 0) {
      if (e.key === "Left" || e.key === "ArrowLeft") {
        e.preventDefault();
      }
    }
  };

  const cursorPosition = () => {
    const input = document.querySelector(
      `[data-spotlight-id="input-field-box"] > input`
    );
    if (input) {
      setPosition(input.selectionStart);
    }
  };

  const onCancel = useCallback(() => {
    if (!isOnTopRef.current) {
      return;
    }
    if (searchQuery === null || searchQuery === "") {
      dispatch(popPanel(panel_names.SEARCH_PANEL));
    } else {
      setSearchQuery("");
      setCurrentPage(1);
      dispatch(resetSearch());
      Spotlight.focus("search-input-box");
    }
  }, [searchQuery, dispatch]);

  const onFocusedContainerId = useCallback(
    (containerId) => {
      setFocusedContainerId(containerId);
      if (!firstSpot) {
        setTimeout(() => {
          Spotlight.resume();
          setFirstSpot(true);
          if (panelInfo.currentSpot) {
            if (panels[panels.length - 1]?.name === "searchpanel") {
              Spotlight.focus(panelInfo.currentSpot);
            }
          }
        }, 0);
      }
    },
    [panelInfo, firstSpot]
  );

  const panelInfoFall = useMemo(() => {
    const newPanelInfo = { ...panelInfo };
    if (firstSpot) {
      newPanelInfo.currentSpot = null;
    }
    return newPanelInfo;
  }, [panelInfo, firstSpot]);

  return (
    <TPanel
      className={css.container}
      handleCancel={onCancel}
      spotlightId={spotlightId}
    >
      <TBody
        className={css.tBody}
        scrollable={false}
        spotlightDisabled={!isOnTop}
      >
        <ContainerBasic>
          {isOnTop && (
            <TVerticalPagenator
              className={css.tVerticalPagenator}
              spotlightId={"search_verticalPagenator"}
              defaultContainerId={panelInfo?.focusedContainerId}
              disabled={!isOnTop}
              // onScrollStop={onScrollStop}
              onFocusedContainerId={onFocusedContainerId}
              cbChangePageRef={cbChangePageRef}
              topMargin={36}
            >
              <ContainerBasic
                className={css.inputContainer}
                data-wheel-point={true}
                spotlightId={"search-input-layer"}
              >
                <TInput
                  className={css.inputBox}
                  kind={KINDS.withIcon}
                  icon={ICONS.search}
                  value={searchQuery}
                  onChange={handleSearchChange}
                  onIconClick={() => handleSearchSubmit(searchQuery)}
                  onKeyDown={handleKeydown}
                  onKeyUp={cursorPosition}
                  forcedSpotlight="first-keyword-button"
                  spotlightId={"search-input-box"}
                />
              </ContainerBasic>

              {searchPerformed && searchQuery !== null ? (
                Object.keys(searchDatas).length > 0 ? (
                  <SearchResults
                    panelInfo={panelInfoFall}
                    searchQueryRef={searchQueryRef}
                    isRecommendedSearchRef={isRecommendedSearchRef}
                  />
                ) : (
                  <NoSearchResults />
                )
              ) : (
                <ContainerBasic>
                  <RecommendedKeywords
                    keywords={paginatedKeywords}
                    onPrev={handlePrev}
                    onNext={handleNext}
                    hasPrevPage={hasPrevPage}
                    hasNextPage={hasNextPage}
                    handleSearchSubmit={handleSearchSubmit}
                    isRecommendedSearchRef={isRecommendedSearchRef}
                  />
                </ContainerBasic>
              )}
            </TVerticalPagenator>
          )}
        </ContainerBasic>
      </TBody>
    </TPanel>
  );
}
