import React, { useEffect, useRef, useState } from 'react';
import { PDFViewer, EventBus, PDFLinkService, NullL10n } from 'pdfjs-dist/legacy/web/pdf_viewer';
import { getDocument, GlobalWorkerOptions, CMapCompressionType, PasswordResponses } from 'pdfjs-dist/legacy/build/pdf';
import { withAnalyticsEvents } from '@atlaskit/analytics-next';
import { cmap } from './cmaps';
import { ZoomControls } from '../../zoomControls';
import { PDFWrapper } from '../../styleWrappers';
import { closeOnDirectClick } from '../../utils/closeOnDirectClick';
import { Outcome } from '../../domain';
import { Spinner } from '../../loading';
import ErrorMessage from '../../errorMessage';
import { ZoomLevel } from '../../domain/zoomLevel';
import { processError } from './processError';
import { pdfJs } from './pdfJs';
import { extractCompressedBase64 } from './extractCompressedBase64';
import { PDFPasswordInput } from './pdfPasswordInput';
import { fireAnalytics } from '../../analytics';
import { createPdfPasswordInputScreenEvent } from '../../analytics/events/screen/pdfPasswordInput';
import { createPasswordPdfScreenEvent } from '../../analytics/events/screen/passwordPdf';
import { PDFRendererWrapper } from './pdfRendererWrapper';
export const pdfViewerClassName = 'pdfViewer';
class CmapFactory {
  constructor() {}
  async fetch({
    name
  }) {
    const module = await cmap[name]();
    const data = await extractCompressedBase64(module.default);
    return {
      cMapData: data,
      compressionType: CMapCompressionType.BINARY
    };
  }
}
let defaultWorkerUrl = '';
const PDFRendererBase = ({
  src,
  onClose,
  onSuccess,
  onError,
  workerUrl,
  item,
  createAnalyticsEvent
}) => {
  const [zoomLevel, setZoomLevel] = useState(new ZoomLevel(1));
  const [docOutcome, setDocOutcome] = useState(Outcome.pending());
  const isPasswordPdfRef = useRef(false);
  const [passwordProtected, setPasswordProtected] = useState(false);
  const [hasPasswordError, setHasPasswordError] = useState(false);
  const pdfWrapperRef = useRef();
  const docRef = useRef();
  const pdfViewerRef = useRef();
  const onSuccessRef = useRef(onSuccess);
  onSuccessRef.current = onSuccess;
  const updatePasswordRef = useRef(undefined);
  const onErrorRef = useRef(onError);
  onErrorRef.current = onError;
  const existingGlobalWorkerRef = useRef(undefined);
  useEffect(() => {
    /**
     * CXP-4622: Fixes issue of PDF.js reusing the global worker registered by embeded PDF macro in confluence
     * The global worker will likely be a different version and thus throw an error.
     * This will remove the worker on mount and will re-register it on unmount
     */
    const {
      pdfjsWorker
    } = window;
    if (pdfjsWorker) {
      existingGlobalWorkerRef.current = pdfjsWorker;
      window.pdfjsWorker = undefined;
    }
    let isSubscribed = true;
    const fetchDoc = async () => {
      try {
        if (!workerUrl && !defaultWorkerUrl) {
          const blob = await extractCompressedBase64(pdfJs, 'blob');
          defaultWorkerUrl = URL.createObjectURL(blob);
        }
        GlobalWorkerOptions.workerSrc = workerUrl !== null && workerUrl !== void 0 ? workerUrl : defaultWorkerUrl;
        const getDocumentTask = getDocument({
          url: src,
          CMapReaderFactory: CmapFactory,
          isEvalSupported: false
        });
        getDocumentTask.onPassword = (updatePassword, e) => {
          updatePasswordRef.current = updatePassword;
          if (e === PasswordResponses.NEED_PASSWORD) {
            isPasswordPdfRef.current = true;
            setPasswordProtected(true);
          } else {
            setHasPasswordError(true);
          }
        };
        docRef.current = await getDocumentTask.promise;
        isSubscribed && setDocOutcome(Outcome.successful(docRef.current));
      } catch (error) {
        const pdfError = processError(error);
        isSubscribed && setDocOutcome(Outcome.failed(pdfError));
        if (onErrorRef.current) {
          onErrorRef.current(pdfError);
        }
      }
    };
    fetchDoc();
    return () => {
      isSubscribed = false;
      if (docRef.current) {
        docRef.current.destroy();
      }
      window.pdfjsWorker = existingGlobalWorkerRef.current;
    };
  }, [src, workerUrl]);
  useEffect(() => {
    if (docOutcome.status !== 'SUCCESSFUL' || !pdfWrapperRef.current) {
      return;
    }
    const eventBus = new EventBus();
    const pdfLinkService = new PDFLinkService({
      eventBus
    });
    pdfViewerRef.current = new PDFViewer({
      container: pdfWrapperRef.current,
      eventBus,
      linkService: pdfLinkService,
      l10n: NullL10n
    });
    pdfLinkService.setViewer(pdfViewerRef.current);
    pdfViewerRef.current.setDocument(docRef.current);
    pdfLinkService.setDocument(docRef.current, null);
    pdfViewerRef.current.firstPagePromise.then(scaleToFit);
    if (isPasswordPdfRef.current) {
      fireAnalytics(createPasswordPdfScreenEvent(), createAnalyticsEvent);
    }
    if (onSuccessRef.current) {
      onSuccessRef.current();
    }
  }, [createAnalyticsEvent, docOutcome.status]);
  const savePdfElement = el => {
    pdfWrapperRef.current = el;
  };
  const handleZoom = zoomLevel => {
    pdfViewerRef.current.currentScale = zoomLevel.value;
    setZoomLevel(zoomLevel);
  };
  const scaleToFit = () => {
    if (pdfViewerRef.current) {
      pdfViewerRef.current.currentScaleValue = 'page-width';
      setZoomLevel(new ZoomLevel(pdfViewerRef.current.currentScale));
    }
  };
  return docOutcome.match({
    pending: () => passwordProtected ? /*#__PURE__*/React.createElement(PDFPasswordInput, {
      onRender: () => fireAnalytics(createPdfPasswordInputScreenEvent(), createAnalyticsEvent),
      onSubmit: data => {
        var _updatePasswordRef$cu;
        // Reset hasPasswordError on each submission
        hasPasswordError && setHasPasswordError(false);
        (_updatePasswordRef$cu = updatePasswordRef.current) === null || _updatePasswordRef$cu === void 0 ? void 0 : _updatePasswordRef$cu.call(updatePasswordRef, data.password);
      },
      hasPasswordError: hasPasswordError
    }) : /*#__PURE__*/React.createElement(Spinner, null),
    successful: () => /*#__PURE__*/React.createElement(PDFRendererWrapper, null, /*#__PURE__*/React.createElement(PDFWrapper, {
      "data-testid": "media-viewer-pdf-content",
      ref: savePdfElement
    },
    /*#__PURE__*/
    // eslint-disable-next-line @atlaskit/design-system/prefer-primitives, @atlassian/a11y/click-events-have-key-events, @atlassian/a11y/interactive-element-not-keyboard-focusable, @atlassian/a11y/no-static-element-interactions
    React.createElement("div", {
      // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
      className: pdfViewerClassName,
      onClick: closeOnDirectClick(onClose)
    }), /*#__PURE__*/React.createElement(ZoomControls, {
      zoomLevel: zoomLevel,
      onChange: handleZoom
    }))),
    failed: error => {
      return /*#__PURE__*/React.createElement(ErrorMessage, {
        fileId: item.id,
        fileState: item,
        error: error,
        supressAnalytics: true // item-viewer.tsx will send
      });
    }
  });
};
export const PDFRenderer = withAnalyticsEvents()(PDFRendererBase);