import {
  type FC,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import { useQuery } from 'react-query';

import NavigateBeforeIcon from '@material-hu/icons/material/NavigateBefore';
import NavigateNextIcon from '@material-hu/icons/material/NavigateNext';
import CircularProgress from '@material-hu/mui/CircularProgress';
import Stack from '@material-hu/mui/Stack';

import { Document } from 'src/config/react-pdf';
import { defaultDimensions } from 'src/hooks/useDimensions';
import { usePdfDimensions } from 'src/hooks/usePdfDimensions';
import { type Attachment, FileTypes } from 'src/types/attachments';
import { type File } from 'src/types/files';
import { getBlobCloudfrontDocument, isSecureFile } from 'src/utils/documents';
import {
  getBlobUrl,
  isFileSupported,
  isFolder,
  isImageFile,
  isPdf,
  isVideoFile,
} from 'src/utils/files';
import { useLokaliseTranslation } from 'src/utils/i18n';

import DialogFilePreview from 'src/components/attachment/DialogFilePreview';
import MediaBase from 'src/components/attachment/MediaBase';
import PdfPageWithObserver from 'src/components/attachment/PdfPageWithObserver';
import {
  FileNotSupported,
  Header,
  NavigationButton,
  ToolContainer,
} from 'src/components/attachment/preview';
import { type HeaderProps } from 'src/components/attachment/preview/Header';

export type FilePreviewProps = {
  open: boolean;
  currentFile: Partial<File> & Partial<Attachment>;
  onGoBack?: () => void;
  onGoForward?: () => void;
  isNavigationButtonGoBackDisabled?: boolean;
  isNavigationButtonGoForwardDisabled?: boolean;
  isLoadingMedia?: boolean;
  isPost?: boolean;
  headerProps?: Pick<HeaderProps, 'allowDownload' | 'onDownload' | 'onClose'>;
};

export const FilePreview = (props: FilePreviewProps) => {
  const {
    currentFile,
    onGoBack,
    onGoForward,
    isNavigationButtonGoBackDisabled,
    isNavigationButtonGoForwardDisabled,
    isLoadingMedia = false,
    open = false,
    isPost = false,
    headerProps = {
      allowDownload: true,
      onDownload: () => null,
      onClose: () => null,
    },
  } = props;

  const { t } = useLokaliseTranslation('files');

  const [numPages, setNumPages] = useState<number | null>(null);
  const [pageNumber, setPageNumber] = useState(1);
  const [isLoading, setIsLoading] = useState(true);
  const [zoomValue, setZoomValue] = useState(1);
  const [showButtons, setShowButtons] = useState(true);

  const fileSource = currentFile?.source;
  const secureFileBlob = useQuery(
    ['secureFileBlob', fileSource],
    () => getBlobCloudfrontDocument(fileSource as string),
    {
      enabled: !!fileSource && isSecureFile(fileSource),
    },
  );

  const blobUrl = useMemo(() => {
    if (secureFileBlob.data) {
      return getBlobUrl(secureFileBlob.data);
    }
    return fileSource ?? currentFile?.url;
  }, [secureFileBlob.data, fileSource, currentFile?.url]);

  const {
    ref: documentRef,
    dimensions: pageDimensions,
    handleLoadPage,
  } = usePdfDimensions();

  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const handleResetTimeout = useCallback(() => {
    setShowButtons(true);
    if (timerRef.current !== null) {
      clearTimeout(timerRef.current);
    }
    timerRef.current = setTimeout(() => setShowButtons(false), 3000);
  }, []);

  useEffect(() => {
    setNumPages(null);
    setPageNumber(1);
    setZoomValue(1);
  }, [currentFile?.id]);

  useEffect(() => {
    window.addEventListener('mousemove', handleResetTimeout);

    return () => {
      window.removeEventListener('mousemove', handleResetTimeout);
      if (timerRef.current !== null) {
        clearTimeout(timerRef.current);
      }
    };
  }, [handleResetTimeout]);

  const handleUpdatePageNumber = (newPageNumber: number) => {
    handleResetTimeout();
    setPageNumber(newPageNumber);
  };

  const onDocumentLoadSuccess = ({
    numPages: newNumPages,
  }: {
    numPages: number;
  }) => {
    setNumPages(newNumPages);
    setIsLoading(false);
  };

  const handleGoBack = () => {
    setIsLoading(true);
    onGoBack?.();
  };

  const handleGoForward = () => {
    setIsLoading(true);
    onGoForward?.();
  };

  const handleOnClose = () => {
    setPageNumber(1);
    setZoomValue(1);
    headerProps.onClose();
  };

  const handleZoomValue = (newZoomValue: number) => setZoomValue(newZoomValue);

  return (
    <DialogFilePreview
      open={open}
      onClose={handleOnClose}
      maxWidth="lg"
      sx={{
        '& .MuiPaper-root': {
          overflow: isPdf(currentFile?.extension ?? undefined)
            ? 'scroll'
            : 'visible',
          width: isPdf(currentFile?.extension ?? undefined) ? '100%' : 'auto',
        },
      }}
    >
      {!isLoadingMedia && (
        <Header
          file={currentFile}
          fileSource={blobUrl ?? currentFile?.url ?? ''}
          {...headerProps}
          onClose={headerProps.onClose}
        />
      )}
      {isLoadingMedia && (
        <Stack sx={{ textAlign: 'center' }}>
          <CircularProgress />
        </Stack>
      )}
      {isImageFile(currentFile?.extension?.toLowerCase(), currentFile?.type) &&
        !isFolder(currentFile.type) &&
        !isLoadingMedia && (
          <MediaBase
            hasZoom
            media={{
              ...currentFile,
              type: FileTypes.IMAGE,
              name: currentFile?.name ?? '',
            }}
            onClick={e => e.stopPropagation()}
            initialZoom={isPost}
          />
        )}
      {isVideoFile(currentFile?.extension?.toLowerCase(), currentFile?.type) &&
        !isFolder(currentFile?.type) &&
        !isLoadingMedia && (
          <MediaBase
            hasZoom
            media={{
              ...currentFile,
              type: FileTypes.VIDEO,
              name: currentFile?.name ?? '',
            }}
            onClick={e => e.stopPropagation()}
            initialZoom
            defaultMuted={false}
          />
        )}
      {isPdf(currentFile?.extension?.toLowerCase()) &&
        !isFolder(currentFile.type) &&
        !isLoadingMedia && (
          <Stack
            sx={{
              width: '100%',
              height: '100vh',
              display: 'flex',
              justifyContent: 'center',
              alignItems: 'center',
              '& .react-pdf__Document': {
                width: '100%',
                maxWidth: '594px',
              },
            }}
          >
            <Document
              file={blobUrl ?? undefined}
              key={currentFile?.id}
              onLoadSuccess={onDocumentLoadSuccess}
              inputRef={documentRef}
              loading={
                <Stack sx={{ alignItems: 'center' }}>
                  <CircularProgress color="primary" />
                </Stack>
              }
              externalLinkTarget="_blank"
            >
              {Array.from(new Array(numPages ?? 0), (_el, index) => (
                <PdfPageWithObserver
                  key={index}
                  index={index}
                  zoomValue={zoomValue}
                  onUpdatePageNumber={handleUpdatePageNumber}
                  onLoadSuccess={handleLoadPage}
                  dimensions={{
                    width: pageDimensions.width ?? defaultDimensions.width,
                    height: pageDimensions.height ?? defaultDimensions.height,
                  }}
                />
              ))}
            </Document>
          </Stack>
        )}
      {!isFileSupported(
        currentFile?.extension?.toLowerCase(),
        currentFile?.type,
      ) &&
        !isLoadingMedia && (
          <FileNotSupported
            fileName={currentFile?.name ?? ''}
            fileSource={blobUrl ?? ''}
            title={
              isFolder(currentFile.type)
                ? t('NOT_SUPPORTED_MESSAGE_FOLDER')
                : t('NOT_SUPPORTED_MESSAGE')
            }
            isFolder={isFolder(currentFile.type)}
            allowDownload={headerProps.allowDownload}
          />
        )}
      {isPdf(currentFile?.extension?.toLowerCase() ?? undefined) &&
        showButtons && (
          <ToolContainer
            isPdf={isPdf(currentFile?.extension ?? undefined)}
            onLoadMedia={!isLoading}
            pageNumber={pageNumber}
            totalPages={numPages ?? 0}
            onZoom={handleZoomValue}
            zoomValue={zoomValue}
          />
        )}
      {!isNavigationButtonGoBackDisabled && !isLoadingMedia && (
        <NavigationButton
          NavigationIcon={NavigateBeforeIcon}
          onClick={handleGoBack}
        />
      )}
      {!isNavigationButtonGoForwardDisabled && !isLoadingMedia && (
        <NavigationButton
          NavigationIcon={NavigateNextIcon}
          onClick={handleGoForward}
          isNext
        />
      )}
    </DialogFilePreview>
  );
};

export default FilePreview;
