import { FC, useState, useRef, useEffect } from 'react';
import { useForm, FormProvider } from 'react-hook-form';

import { useQuery, useMutation } from 'react-query';
import { useParams, useNavigate } from 'react-router-dom';

import { AxiosError } from 'axios';
import { differenceInSeconds, parse } from 'date-fns';

import Add from '@material-hu/icons/material/Add';
import Remove from '@material-hu/icons/material/Remove';
import Box from '@material-hu/mui/Box';
import { useTheme } from '@material-hu/mui/styles';
import CircularProgress from '@material-hu/mui/CircularProgress';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import Tooltip from '@material-hu/mui/Tooltip';
import Typography from '@material-hu/mui/Typography';

import Button from '@material-hu/components/design-system/Buttons/Button';
import useSnackbar from '@material-hu/components/design-system/Snackbar';

import { logEvent } from 'src/config/logging';
import { Document, Page } from 'src/config/react-pdf';
import { useAuth } from 'src/contexts/JWTContext';
import useFormatDate from 'src/hooks/useFormatDate';
import useGeneralError from 'src/hooks/useGeneralError';
import { useSecureFileUrl } from 'src/hooks/useSecureFileUrl';
import { getForm, createForm } from 'src/services/forms';
import { EventName } from 'src/types/amplitude';
import { InputType, FormType } from 'src/types/forms';
import { ResponseError } from 'src/types/services';
import { logAmplitudeEvents, userFields } from 'src/utils/form';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getCurrentLocale } from 'src/utils/locale';

import GetPdfInputComponent from 'src/components/dashboard/form/pdfForm/GetPdfInputComponent';
import PdfPaginator from 'src/components/dashboard/form/pdfForm/PdfPaginator';
import { formKeys } from 'src/components/dashboard/form/queries';
import { formRoutes } from 'src/components/dashboard/form/routes';
import GoBackButton from 'src/components/dashboard/GoBackButton';

const { AUTOCOMPLETE, DIGITAL_SIGN } = InputType;

/**
 * PDF.js configuration options for enhanced rendering
 *
 * cMapUrl: URL for Character Map files needed for non-Latin text (Chinese, Japanese, Korean, etc.)
 * cMapPacked: Use compressed CMaps for better performance
 *
 * These settings ensure forms display correctly with international characters
 * Works alongside the PDF worker configuration in src/config/react-pdf.ts
 */
const PDF_OPTIONS = {
  cMapUrl: 'https://unpkg.com/pdfjs-dist@3.4.120/cmaps/',
  cMapPacked: true,
};

const MAX_ZOOM = 5;
const MIN_ZOOM = 1;

const FormPdf: FC = () => {
  const { id } = useParams();
  const theme = useTheme();
  const { formatDate } = useFormatDate();
  const { user } = useAuth();

  const [currentPage, setCurrentPage] = useState(1);
  // eslint-disable-next-line react/hook-use-state
  const [startTime] = useState(new Date());
  const [zoomFactor, setZoomFactor] = useState<number>(1);

  // Container ref to measure for dynamic width
  const containerRef = useRef<HTMLDivElement | null>(null);
  const [containerWidth, setContainerWidth] = useState<number | null>(null);
  const [isPdfLoaded, setIsPdfLoaded] = useState(false);

  const navigate = useNavigate();
  const { t } = useLokaliseTranslation('forms');
  const showGeneralError = useGeneralError();
  const { enqueueSnackbar } = useSnackbar();
  const form = useForm();

  const {
    handleSubmit,
    reset,
    formState: { isSubmitting, isValid, dirtyFields },
  } = form;

  const { data } = useQuery(
    formKeys.description(id as string),
    () => getForm(id!),
    {
      onSuccess: () => {
        logEvent(EventName.FORM_START, { formId: id, formPDF: true });
      },
      onError: (err: AxiosError<ResponseError>) => {
        showGeneralError(err, t('DETAIL_FORM_ERROR'));
      },
    },
  );

  const { mutate, isLoading: isLoadingCreateForm } = useMutation(
    (body: any) => {
      const { id: createId, ...formData } = body;
      return createForm(createId, formData);
    },
    {
      onSuccess: response => {
        logAmplitudeEvents(data?.data, response);
        reset();
        enqueueSnackbar({ title: t('SEND_FORM_SUCCESS'), variant: 'success' });

        if (data?.data?.needApproval) {
          navigate(
            formRoutes.form.approvalWorkflow(
              data?.data?.type,
              response?.data?.id,
            ),
            { replace: true },
          );
        } else {
          navigate(
            formRoutes.form.chat(
              data?.data?.type ?? '',
              response?.data?.chat?.id,
            ),
            { replace: true },
          );
        }
      },
    },
  );

  const title = data?.data?.title;
  const inputs = data?.data?.steps?.[0]?.questions || [];

  const pdfUrl = useSecureFileUrl(data?.data?.steps?.[0]?.source ?? '');
  const {
    totalPages,
    width: pdfWidth = 0,
    height: pdfHeight = 0,
  } = data?.data?.steps?.[0]?.sourceData || {};

  // Enhanced size detection using ResizeObserver if available -> fallback to window resize
  useEffect(() => {
    if (!containerRef.current) return;

    const handleResize = () => {
      if (containerRef.current) {
        setContainerWidth(containerRef.current.offsetWidth);
      }
    };

    handleResize(); // Initial measurement

    // Use ResizeObserver if available
    if (typeof ResizeObserver !== 'undefined') {
      const resizeObserver = new ResizeObserver(handleResize);
      resizeObserver.observe(containerRef.current);
      return () => {
        if (containerRef.current) {
          resizeObserver.unobserve(containerRef.current);
        }
        resizeObserver.disconnect();
      };
    } else {
      // Fallback to window resize
      window.addEventListener('resize', handleResize);
      return () => window.removeEventListener('resize', handleResize);
    }
  }, []);

  // Reset scroll position when changing pages
  useEffect(() => {
    if (containerRef.current) {
      containerRef.current.scrollTop = 0;
      containerRef.current.scrollLeft = 0;
    }
  }, [currentPage]);

  const finish = (values: Record<string, any>) => {
    const body = Object.keys(values).map(key => {
      const [inputType, finishId, userField] = key.split('-');
      const value = values[key];
      if (!value) return null;

      if (inputType === DIGITAL_SIGN) {
        return {
          inputType,
          id: Number(finishId),
          attachments: value.answer,
        };
      }

      if (userField === userFields.COMPLETION_DATE) {
        const parsedDate = parse(value, 'P', new Date(), {
          locale: getCurrentLocale(user),
        });
        return {
          inputType,
          answer: [formatDate(parsedDate, 'yyyy-MM-dd')],
          id: Number(finishId),
        };
      }

      return { inputType, answer: [value], id: Number(finishId) };
    });

    const endTime = new Date();
    const fillingTime = differenceInSeconds(endTime, startTime);

    const bodyToSend = {
      id,
      questions: body.filter(e => e),
      fillingTime,
    };
    mutate(bodyToSend);
  };

  const goBack = (e: React.MouseEvent) => {
    e.preventDefault();
    navigate(formRoutes.forms(FormType.FORM));
  };

  const isAutocomplete = (value: string) => value === AUTOCOMPLETE;
  const isLastPage = currentPage === totalPages;
  const noneRequiresAction = inputs.every(
    e => isAutocomplete(e.inputType) || !e.required,
  );
  const touchedInputs = Object.keys(dirtyFields).length;
  const hasInteracted = touchedInputs || noneRequiresAction;

  const canSubmit =
    isLastPage &&
    isValid &&
    hasInteracted &&
    !isLoadingCreateForm &&
    !isSubmitting;

  const handleZoomIn = () => setZoomFactor(z => Math.min(z + 0.25, MAX_ZOOM));
  const handleZoomOut = () => setZoomFactor(z => Math.max(z - 0.25, MIN_ZOOM));

  let renderedPdfWidth = 0;
  let renderedPdfHeight = 0;

  if (containerWidth && pdfWidth > 0 && pdfHeight > 0) {
    renderedPdfWidth = containerWidth * zoomFactor;
    const aspectRatio = pdfHeight / pdfWidth;
    renderedPdfHeight = renderedPdfWidth * aspectRatio;
  }

  const safeInputs = inputs || [];

  const adjustedInputs = safeInputs.map(input => {
    // Safety check for malformed data
    if (!input?.boxData?.x || !input?.boxData?.y) {
      return {
        ...input,
        boxData: {
          ...(input.boxData || {}),
          x: input?.boxData?.x || 0,
          y: input?.boxData?.y || 0,
          width: input?.boxData?.width || 0.2,
          height: input?.boxData?.height || 0.1,
          page: input?.boxData?.page || 0,
          xPx: 0,
          yPx: 0,
          widthPx: 100,
          heightPx: 40,
        },
      };
    }

    const { x, y, width, height } = input.boxData;

    // Convert fractional to pixel-based coordinates
    const leftPx = x * renderedPdfWidth;
    const topPx = y * renderedPdfHeight;
    const boxWidthPx = Math.max(width * renderedPdfWidth, 50); // Ensure minimum size
    const boxHeightPx = Math.max(height * renderedPdfHeight, 20);

    return {
      ...input,
      boxData: {
        ...input.boxData,
        xPx: leftPx,
        yPx: topPx,
        widthPx: boxWidthPx,
        heightPx: boxHeightPx,
      },
    };
  });

  const renderPDF = pdfUrl && containerWidth && pdfWidth > 0 && pdfHeight > 0;

  return (
    <Box
      style={{
        display: 'flex',
        justifyContent: 'center',
        padding: '35px 120px',
        marginBottom: '40px',
      }}
    >
      <FormProvider {...form}>
        <form
          noValidate
          onSubmit={handleSubmit(finish)}
          style={{
            display: 'flex',
            flexDirection: 'column',
            width: '100%',
            maxWidth: '900px',
          }}
        >
          <Box
            style={{
              display: 'flex',
              justifyContent: 'space-between',
              alignItems: 'baseline',
              marginBottom: '10px',
            }}
          >
            <Box
              style={{ display: 'flex', gap: '10px', alignItems: 'baseline' }}
            >
              <GoBackButton onClick={goBack} />
              <Typography
                noWrap
                overflow="hidden"
                textOverflow="ellipsis"
                variant="h5"
                sx={{
                  maxWidth: '60%',
                  color: theme.palette.new.text.neutral.default,
                }}
              >
                {title}
              </Typography>
            </Box>
            <Tooltip
              title={canSubmit ? t('FINISH') : t('PDF_COMPLETE_AND_READ')}
            >
              <span>
                <Button
                  disabled={!canSubmit}
                  variant="contained"
                  type="submit"
                >
                  {t('FINISH')}
                </Button>
              </span>
            </Tooltip>
          </Box>
          <Box
            style={{
              display: 'flex',
              justifyContent: 'space-between',
              marginBottom: '10px',
            }}
          >
            <Box style={{ display: 'flex', flexDirection: 'column' }}>
              <Typography
                variant="body2"
                sx={{ color: theme.palette.new.text.neutral.default }}
              >
                {t('REVIEW_DOCUMENT')}
              </Typography>
              <Typography
                variant="body2"
                sx={{ color: theme.palette.new.text.neutral.default }}
              >
                {t('MANDATORY_FIELDS')}
              </Typography>
            </Box>
          </Box>
          {/* Pagination & Zoom */}
          <Stack
            sx={{
              flex: 1,
              gap: 1,
              flexDirection: 'row',
              alignItems: 'center',
              position: 'relative',
              justifyContent: 'center',
              marginBottom: 2,
            }}
          >
            {totalPages && (
              <PdfPaginator
                currentPage={currentPage}
                totalPages={totalPages}
                setCurrentPage={setCurrentPage}
              />
            )}
            <Box
              style={{
                position: 'absolute',
                right: 0,
                gap: 1,
                display: 'flex',
                alignItems: 'center',
              }}
            >
              <IconButton
                onClick={handleZoomOut}
                aria-label="zoom out"
              >
                <Remove />
              </IconButton>
              <Typography
                variant="body2"
                sx={{ color: theme.palette.new.text.neutral.default }}
              >
                {Math.round(zoomFactor * 100)}%
              </Typography>
              <IconButton
                onClick={handleZoomIn}
                aria-label="zoom in"
              >
                <Add />
              </IconButton>
            </Box>
          </Stack>
          {/* PDF Container */}
          <Box
            ref={containerRef}
            style={{
              width: '100%',
              margin: '0 auto',
              overflow: 'auto', // allow scrolling if zoomed in
              height: renderedPdfHeight
                ? `${renderedPdfHeight + 40}px`
                : 'auto', // Add fixed height based on PDF dimensions
              position: 'relative',
            }}
          >
            {renderPDF && (
              <Document
                file={pdfUrl}
                loading={<CircularProgress />}
                onLoadSuccess={() => setIsPdfLoaded(true)}
                options={PDF_OPTIONS}
              >
                <Box
                  style={{
                    position: 'relative',
                    overflow: 'visible',
                  }}
                >
                  <Page
                    loading={<CircularProgress />}
                    renderAnnotationLayer={false}
                    renderTextLayer={false}
                    pageNumber={currentPage}
                    width={renderedPdfWidth}
                    onRenderSuccess={() => {
                      // Force recalculation of container size after page renders
                      if (containerRef.current) {
                        setContainerWidth(containerRef.current.offsetWidth);
                      }
                    }}
                  />
                  {isPdfLoaded &&
                    adjustedInputs
                      .filter(inp => {
                        // Safety check
                        if (inp?.boxData?.page === undefined) return false;

                        return inp.boxData.page === currentPage - 1;
                      })
                      .map(inp => (
                        <GetPdfInputComponent
                          key={inp.id}
                          currentPage={currentPage}
                          {...inp}
                        />
                      ))}
                </Box>
              </Document>
            )}
          </Box>
        </form>
      </FormProvider>
    </Box>
  );
};

export default FormPdf;
