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

import { initialPdfFile, fetchXfdf } from '../apis';
import PdfPages from './PdfPages';
import { fetchPdf } from '../helpers/pdf';
import { scrollIntoView } from '../helpers/utility';
import { parseAnnotationFromXml } from '../helpers/annotation';
import { parseWatermarkFromXml } from '../helpers/watermark';

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

const PdfViewer: React.FC = () => {
  const [
    { viewport, pdf, scale, currentPage, totalPage },
    dispatch,
  ] = useStore();
  const {
    setTotalPage,
    setPdf,
    setProgress,
    setViewport,
    setCurrentPage,
    setInfo,
    addAnnots,
    changeScale,
    updateWatermark,
  } = useActions(dispatch);
  const currentPageRef = useRef(0);

  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 getXfdfFile = (token: string): void => {
    fetchXfdf(token)
      .then(xfdf => {
        const annotations = parseAnnotationFromXml(xfdf);
        const watermark = parseWatermarkFromXml(xfdf);

        if (watermark.obj_attr.type) {
          addAnnots([...annotations, watermark], false);
          updateWatermark(watermark.obj_attr);
        } else {
          addAnnots(annotations, false);
        }
      })
      .catch(error => {
        console.log(error);
      });
  };

  const pdfGenerator = async (): Promise<any> => {
    const parsed = queryString.parse(window.location.search);

    if (parsed.token) {
      const token = parsed.token as string;
      const result = await initialPdfFile(token);

      getXfdfFile(token);
      setInfo({
        token: parsed.token,
        id: result.data.transaction_id,
      });

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

      setTotalPage(iPdf.numPages);
      setPdf(iPdf);

      const page = await iPdf.getPage(1);
      const iViewport = page.getViewport({ scale: 1 });

      iViewport.width = Math.round(iViewport.width);
      iViewport.height = Math.round(iViewport.height);
      const screenWidth = window.document.body.offsetWidth - 5;
      const originPdfWidth = iViewport.width;
      const rate = (screenWidth / originPdfWidth).toFixed(2);

      changeScale(rate);
    }
  };

  const changePdfContainerScale = (): void => {
    for (let i = 1; i <= totalPage; i += 1) {
      const ele: HTMLDivElement = document.getElementById(
        `page_${i}`
      ) as HTMLDivElement;
      if (ele) {
        ele.style.width = `${viewport.width}px`;
        ele.style.height = `${viewport.height}px`;

        if (i === currentPageRef.current) {
          scrollIntoView(ele);
        }
      }
    }
  };

  const scrollToUpdate = (state: ScrollStateType): void => {
    const ele: HTMLDivElement = document.getElementById(
      'page_1'
    ) as HTMLDivElement;
    const page = Math.round(
      (state.lastY + ele.offsetHeight / 1.4) / (ele.offsetHeight + 50)
    );

    if (page !== currentPageRef.current) {
      setCurrentPage(page);
    }
  };

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

  useEffect(() => {
    currentPageRef.current = currentPage;
  }, [currentPage]);

  useEffect(() => {
    if (pdf) {
      changePdfContainerScale();
    }
  }, [viewport]);

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

  return viewport.width ? <PdfPages scrollToUpdate={scrollToUpdate} /> : null;
};

export default PdfViewer;
