import { useRef, useState } from 'react';

import {
  alpha,
  Divider,
  IconButton,
  Stack,
  type SxProps,
  Typography,
  useTheme,
} from '@mui/material';
import { Document } from '@src/config/react-pdf';
import {
  IconArrowsMaximize,
  IconMinus,
  IconPlus,
  IconRotateClockwise2,
} from '@tabler/icons-react';
import { times } from 'lodash';

import useDimensions from '../../../hooks/useDimensions';
import usePdfDimensions from '../../../hooks/usePdfDimensions';
import useResizeObserver from '../../../hooks/useResizeObserver';
import useScroll from '../../../hooks/useScroll';
import { isScrolledToEnd } from '../../../utils/elements';
import '../../../config/react-pdf';

import { useTranslation } from 'react-i18next';

import Spinner from '../../design-system/ProgressIndicators/Spinner';

import PdfFullScreen from './components/FullScreen';
import PdfPage from './components/Page';
import PdfTools from './components/Tools';
import { ANNOTATION_LAYER_STYLES } from './constants';
import { type PdfViewerProps } from './types';
import { getPageWidth, getZoomPercentage, rotate } from './utils';

const MIN_ZOOM_LEVEL = 0.5;

const centeredStackStyles: SxProps = {
  position: 'absolute',
  top: '50%',
  left: '50%',
  transform: 'translate(-50%, -50%)',
  zIndex: 1,
};

const PdfViewer = ({
  name,
  file,
  onFinishRead = () => null,
  variant = 'bar',
  sx,
  slotProps = {},
}: PdfViewerProps) => {
  const [numPages, setNumPages] = useState(0);
  const [pageNumber, setPageNumber] = useState(1);
  const [zoom, setZoom] = useState(1.0);
  const [fullscreen, setFullscreen] = useState(false);
  const [rotation, setRotation] = useState(0);

  const { palette, shape, spacing } = useTheme();
  const { t } = useTranslation('material_hu_only');

  const containerRef = useRef(null);
  const documentRef = useRef(null);
  const { pdfDimensions, navbar } = slotProps;
  const { showRotation = true, showFullScreen = true } = navbar || {};

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

  const { dimensions: containerDimensions } = useDimensions(
    containerRef.current,
  );

  const checkFinishedReading = (container: HTMLElement | null) => {
    if (isScrolledToEnd(container)) onFinishRead();
  };

  useScroll(containerRef.current, checkFinishedReading);

  useResizeObserver(containerRef.current, (entries: ResizeObserverEntry[]) => {
    for (const entry of entries) {
      const element = entry.target as HTMLElement;
      checkFinishedReading(element);
    }
  });

  const handleLoadSuccess = ({ numPages: newNumPages }: any) => {
    setNumPages(newNumPages);
    setPageNumber(1);
  };

  const handleZoomIn = () => setZoom(zoom + 0.1);
  const handleZoomOut = () => setZoom(Math.max(zoom - 0.1, 0.1));

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

  const handleRotate = () => {
    setRotation(rotate(rotation));
  };

  const customDimensions = {
    ...pageDimensions,
    width: getPageWidth(
      zoom,
      containerDimensions.width,
      pdfDimensions?.baseWidth,
    ),
  };

  const handleOpenFullScreen = () => setFullscreen(true);
  const handleCloseFullScreen = () => setFullscreen(false);

  const disableZoomIn = customDimensions.width >= containerDimensions.width;
  const disableZoomOut = zoom <= MIN_ZOOM_LEVEL;
  const isFloating = variant === 'floating';

  return (
    <Stack
      sx={{
        width: '100%',
      }}
    >
      {variant === 'bar' && (
        <Stack
          sx={{
            flexDirection: 'row',
            p: 2,
            gap: 2,
            justifyContent: 'center',
            alignItems: 'center',
            backgroundColor: palette.new.background.elements.inverted,
            borderTopLeftRadius: shape.borderTopLeftRadiusM,
            borderTopRightRadius: shape.borderTopRightRadiusM,
            '& .MuiIconButton-root, .MuiTypography-root, .MuiDivider-root': {
              color: palette.new.text.neutral.inverted,
              '& svg': {
                stroke: palette.new.text.neutral.inverted,
              },
            },
            '& .MuiIconButton-root': {
              '&:hover': {
                backgroundColor: alpha(palette.new.shadows.inverted, 0.5),
              },
            },
            '& .MuiTypography-root': {
              textWrap: 'nowrap',
            },
            '& .MuiDivider-root': {
              height: spacing(2),
            },
            '& .header-group': {
              flexDirection: 'row',
              alignItems: 'center',
              gap: 0.5,
            },
            overflowX: 'auto',
          }}
        >
          {!!numPages && (
            <>
              <Typography className="header-group">
                <span>{pageNumber}</span>
                <span>{'/'}</span>
                <span>{numPages}</span>
              </Typography>
              <Divider orientation="vertical" />
            </>
          )}
          <Stack className="header-group">
            <IconButton
              aria-label={t('hu_pdf.zoom_out')}
              onClick={handleZoomOut}
              disabled={disableZoomOut}
            >
              <IconMinus />
            </IconButton>
            <Typography sx={{ minWidth: '54px', textAlign: 'center' }}>
              {getZoomPercentage(zoom)}
            </Typography>
            <IconButton
              aria-label={t('hu_pdf.zoom_in')}
              onClick={handleZoomIn}
              disabled={disableZoomIn}
            >
              <IconPlus />
            </IconButton>
          </Stack>
          {(showFullScreen || showRotation) && (
            <>
              <Divider orientation="vertical" />
              <Stack className="header-group">
                {showFullScreen && (
                  <IconButton
                    aria-label={t('hu_pdf.full_screen')}
                    onClick={handleOpenFullScreen}
                  >
                    <IconArrowsMaximize />
                  </IconButton>
                )}
                {showRotation && (
                  <IconButton
                    aria-label={t('hu_pdf.rotate')}
                    onClick={handleRotate}
                  >
                    <IconRotateClockwise2 />
                  </IconButton>
                )}
              </Stack>
            </>
          )}
        </Stack>
      )}
      <Stack
        ref={containerRef}
        sx={{
          ...ANNOTATION_LAYER_STYLES,
          width: '100%',
          height: '430px',
          flexDirection: isFloating ? 'column' : 'row',
          display: 'flex',
          justifyContent: isFloating ? 'flex-start' : 'center',
          alignItems: isFloating ? 'center' : 'flex-start',
          backgroundColor: palette.new.background.elements.grey,
          overflow: 'auto',
          position: 'relative',
          ...sx,
        }}
      >
        <Document
          file={file}
          inputRef={documentRef}
          onLoadSuccess={handleLoadSuccess}
          rotate={showRotation ? rotation : null}
          externalLinkTarget="_blank"
          error={
            <Stack sx={centeredStackStyles}>
              {t('hu_pdf.error_loading_pdf')}
            </Stack>
          }
          loading={
            <Stack sx={centeredStackStyles}>
              <Spinner />
            </Stack>
          }
        >
          {times(numPages, index => (
            <PdfPage
              key={index}
              variant={variant}
              page={index + 1}
              zoom={zoom}
              onUpdatePageNumber={handleUpdatePageNumber}
              onLoadSuccess={handleLoadPage}
              dimensions={customDimensions}
            />
          ))}
        </Document>
        {isFloating && (
          <PdfTools
            pageNumber={pageNumber}
            totalPages={numPages}
            onZoom={setZoom}
            zoom={zoom}
            variant={variant}
            toolsOptions={{
              showResetZoom: false,
              showPercentage: true,
            }}
          />
        )}
        {fullscreen && (
          <PdfFullScreen
            name={name}
            file={file}
            onClose={handleCloseFullScreen}
            {...slotProps.fullscreen}
          />
        )}
      </Stack>
    </Stack>
  );
};

export default PdfViewer;
