import React, { useState, useEffect } from 'react';

import useActions from '../actions';
import useStore from '../store';
import SearchComponent from '../components/Search';
import { normalize, calcFindPhraseMatch } from '../helpers/pdf';
import { scrollIntoView } from '../helpers/utility';

type MatchType = {
  page: number;
  index: number;
};

const Search: React.FC = () => {
  let queryString = '';
  const [matchesMap, setMatchesMap] = useState<MatchType[]>([]);
  const [matchTotal, setMatchTotal] = useState(0);
  const [currentIndex, setCurrentIndex] = useState(-1);
  const [{ navbarState, pdf, totalPage }, dispatch] = useStore();
  const { setNavbar } = useActions(dispatch);

  const extractTextItems = async (pageNum: number): Promise<string[]> => {
    const page = await pdf.getPage(pageNum);
    const textContent = await page.getTextContent({
      normalizeWhitespace: true,
    });
    const { items } = textContent;
    const strBuf = [];

    for (let j = 0, len = items.length; j < len; j += 1) {
      if (items[j].str.match(/[^\s]/)) {
        strBuf.push(items[j].str);
      }
    }

    return strBuf;
  };

  const getMatchTextIndex = async (pageNum: number): Promise<void> => {
    const contentItems = await extractTextItems(pageNum);
    const content = normalize(contentItems.join('').toLowerCase());
    const matches = calcFindPhraseMatch(content, queryString);
    if (matches.length) {
      matches.forEach(ele => {
        matchesMap.push({
          page: pageNum,
          index: ele,
        });
      });

      setMatchesMap(matchesMap);
      setMatchTotal(cur => cur + matches.length);
    }

    if (pageNum < totalPage) {
      getMatchTextIndex(pageNum + 1);
    }
  };

  const searchPdfPages = async (): Promise<void> => {
    getMatchTextIndex(1);
  };

  const cleanMatch = (): void => {
    setMatchTotal(0);
    setCurrentIndex(-1);
    setMatchesMap([]);
  };

  const handleSearch = (val: string): void => {
    cleanMatch();

    if (val) {
      queryString = val.toLowerCase();
      searchPdfPages();
    }
  };

  const clickPrev = (): void => {
    setCurrentIndex(cur => {
      if (cur > 0) {
        return cur - 1;
      }
      return cur;
    });
  };

  const clickNext = (): void => {
    setCurrentIndex(cur => {
      if (cur + 1 < matchTotal) {
        return cur + 1;
      }
      return cur;
    });
  };

  const handleClose = (): void => {
    setNavbar('');
    cleanMatch();
  };

  useEffect(() => {
    if (matchTotal === 1) {
      clickNext();
    }
  }, [matchTotal]);

  useEffect(() => {
    if (currentIndex >= 0) {
      const indexObj = matchesMap[currentIndex];
      const pageDiv: HTMLDivElement = document.getElementById(
        `page_${indexObj.page}`
      ) as HTMLDivElement;
      scrollIntoView(pageDiv);
    }
  }, [currentIndex, matchesMap]);

  return (
    <SearchComponent
      matchesTotal={matchTotal}
      current={currentIndex + 1}
      onPrev={clickPrev}
      onNext={clickNext}
      onEnter={handleSearch}
      isActive={navbarState === 'search'}
      close={handleClose}
    />
  );
};

export default Search;
