import React, {
  useEffect, useState, useRef, useCallback,
} from 'react';
import queryString from 'query-string';
import config from '../config';
import apiPath from '../constants/apiPath';

import { initialPdfFile } from '../apis';
import Viewer from '../components/Viewer';
import { fetchPdf } from '../helpers/pdf';
import { watchScroll } from '../helpers/utility';
import { ProgressType, ScrollStateType } from '../constants/type';

import useActions from '../actions';
import useStore from '../store';

const PdfViewer: React.FunctionComponent = () => {
  const containerRef = useRef<HTMLDivElement>(null);
  const pageRef = useRef(1);
  const viewportRef = useRef({ height: 0, width: 0 });
  const [initialized, setInitialize] = useState(false);
  const [{
    totalPage, currentPage, viewport, pdf, scale, rotation,
  }, dispatch] = useStore();
  const {
    setTotalPage, setCurrentPage, setPdf, setProgress, setViewport,
  } = useActions(dispatch);

  const setLoadingProgress = (totalSize: number) => (progress: ProgressType): void => {
    setProgress({
      total: totalSize,
      loaded: progress.loaded,
    });
  };

  const getViewport = async (pdfEle: any, s: number): Promise<any> => {
    const page = await pdfEle.getPage(1);
    const iViewport = page.getViewport({ scale: s });

    iViewport.width = Math.round(iViewport.width);
    iViewport.height = Math.round(iViewport.height);
    setViewport(iViewport);
  };

  const pdfGenerator = async (): Promise<any> => {
    const parsed = queryString.parse(window.location.search);
    const res = await initialPdfFile(parsed.token as string);

    if (res.data) {
      const iPdf = await fetchPdf(
        `${config.API_HOST}${apiPath.getOriginalPdfFile}?transaction_id=${res.data.transaction_id}`,
        setLoadingProgress(res.data.size),
      );

      const totalNum = iPdf.numPages;
      setTotalPage(totalNum);
      setPdf(iPdf);

      await getViewport(iPdf, 1);
      setInitialize(true);
    }
  };

  const scrollUpdate = useCallback((state: ScrollStateType) => {
    const iViewport = viewportRef.current;
    const page = Math.round((state.lastY + iViewport.height / 1.4) / (iViewport.height + 50));
    if (page !== pageRef.current) {
      setCurrentPage(page);
    }
  }, [dispatch]);

  useEffect(() => {
    pdfGenerator();
  }, []);

  useEffect(() => {
    if (containerRef.current) {
      watchScroll(containerRef.current, scrollUpdate);
    }
  }, [initialized]);

  useEffect(() => {
    pageRef.current = currentPage;
    viewportRef.current = viewport;
  }, [currentPage, viewport]);

  useEffect(() => {
    if (pdf) {
      getViewport(pdf, scale);
    }
  }, [scale]);

  return (
    initialized ? (
      <Viewer
        ref={containerRef}
        totalPage={totalPage}
        currentPage={currentPage}
        viewport={viewport}
        pdf={pdf}
        rotation={rotation}
      />
    ) : null
  );
};

export default PdfViewer;
