import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {
  LayoutChangeEvent,
  LayoutRectangle,
  Pressable,
  View,
} from 'react-native';
import {useTranslation} from 'react-i18next';
import Pdf from 'react-native-pdf';
import {
  IconChevronDown,
  IconChevronRight,
  IconInfoCircle,
} from '@tabler/icons-react-native';
import {useNavigation} from '@react-navigation/native';
import {useFormContext} from 'react-hook-form';
import {ReactNativeZoomableView} from '@openspacelabs/react-native-zoomable-view';
import {
  BackButton,
  BottomModalFooter,
  Button,
  CloseButton,
  Dialog,
  IconButton,
  Menu,
  Typography,
} from '@components';
import {useModalHandler} from '@hooks/useModalHandler';
import {showSnackbar} from '@redux/dispatchers';
import {SPACING, useTheme} from '@shared/theme';
import {
  DynamicFormComponent,
  NextSection,
  PageMeta,
  PdfMeta,
} from '@shared/dynamicForms/interfaces';
import {windowDimensions} from '@shared/constants';
import {PdfFontScaleProvider} from '@shared/dynamicForms/contexts/PdfFontScaleContext';

import {styles} from './styles';
import {computePdfMapping, mapPdfRectToScreen} from './utils';
import PdfFormInput from '../PdfFormInput';
import {FormDescription} from '../FormDescription';

interface Props {
  pdfMeta: PdfMeta;
  nextSection: NextSection;
  disableSendButton: boolean;
  isLoading: boolean;
  onSubmit: () => void;
  description?: string;
  richDescription?: string;
}

function PdfFormContainer({
  pdfMeta: {pageCount, pages, uri},
  nextSection,
  disableSendButton,
  isLoading,
  onSubmit,
  description,
  richDescription,
}: Props) {
  const {theme} = useTheme();
  const {
    content: {components},
  } = nextSection;
  const {t} = useTranslation();
  const navigation = useNavigation();
  const [containerLayout, setContainerLayout] =
    useState<Nullable<LayoutRectangle>>(null);
  const [page, setPage] = useState<number>(0);
  const {
    formState: {errors},
  } = useFormContext();
  const pageModal = useModalHandler();
  const infoModal = useModalHandler();
  const containerWidth = containerLayout?.width ?? 0;
  const containerHeight = containerLayout?.height ?? 0;
  const pageWidth = pages[page].width;
  const pageHeight = pages[page].height;

  const onContainerLayout = useCallback((event: LayoutChangeEvent) => {
    setContainerLayout(event.nativeEvent.layout);
  }, []);

  useEffect(() => {
    const errorLength = Object.keys(errors).length;
    if (errorLength > 0) {
      showSnackbar({
        title: t('service_management.required_fields_helper_text', {
          count: errorLength,
        }),
        description: t('service_management.incomplete_fields_helper_text'),
        variant: 'error',
      });

      const errorComponent = components.find(
        component =>
          component.nameId ===
          Object.keys(errors)[0].split(`${nextSection.nameId}-`)[1],
      );
      if (errorComponent) {
        const {pdfLayout} = errorComponent;
        pdfLayout && setPage(pdfLayout.page - 1);
      }
    }
  }, [components, errors, nextSection.nameId, t]);

  useEffect(() => {
    const headerLeft = () =>
      page !== 0 ? (
        <BackButton onPress={() => setPage(prev => Math.max(prev - 1, 0))} />
      ) : null;
    const headerRight = () => (
      <View style={styles.headerRightContainer}>
        {description && (
          <IconButton
            Icon={IconInfoCircle}
            onPress={infoModal.onOpenModal}
            variant="flat"
            hitSlop={SPACING.x2}
          />
        )}
        <CloseButton onPress={navigation.goBack} />
      </View>
    );
    navigation.setOptions({
      headerLeft,
      headerRight,
    });
  }, [description, infoModal.onOpenModal, navigation, page]);

  const mapping = useMemo(
    () =>
      computePdfMapping({
        fitPolicy: 0,
        containerWidth,
        containerHeight,
        pageWidth,
        pageHeight,
      }),
    [containerWidth, containerHeight, pageWidth, pageHeight],
  );

  const renderInput = useCallback(
    (component: DynamicFormComponent) => {
      const {pdfLayout} = component;
      if (!pdfLayout || pdfLayout.page !== page + 1) {
        return null;
      }

      const {left, top, width, height} = mapPdfRectToScreen({
        rectRel: {
          x: pdfLayout.x,
          y: pdfLayout.y,
          width: pdfLayout.width,
          height: pdfLayout.height,
        },
        pageWidth,
        pageHeight,
        scale: mapping.baseScale,
        offsetX: mapping.offsetX,
        offsetY: mapping.offsetY,
      });

      return (
        <PdfFormInput
          key={component.nameId}
          layout={{left, top, width, height}}
          component={component}
          section={nextSection.nameId}
        />
      );
    },
    [
      mapping.baseScale,
      mapping.offsetX,
      mapping.offsetY,
      nextSection.nameId,
      page,
      pageHeight,
      pageWidth,
    ],
  );

  const renderPageItem = useCallback(
    ({item}: {item: PageMeta}) => {
      const onPress = () => {
        setPage(item.index);
        pageModal.onCloseModal();
      };

      return (
        <Pressable style={styles.pageItem} onPress={onPress}>
          <Typography weight="semiBold">{`${t('service_management.page')} ${
            item.index + 1
          }`}</Typography>
          <IconChevronRight />
        </Pressable>
      );
    },
    [t, pageModal],
  );

  const onPressButton = () => {
    if (page === pageCount - 1) {
      onSubmit();
    } else {
      setPage(prev => Math.min(prev + 1, pageCount - 1));
    }
  };

  return (
    <PdfFontScaleProvider fontScale={mapping.baseScale}>
      <View style={styles.container} key={page}>
        {pageCount > 1 && (
          <View
            style={[
              styles.headerContainer,
              {backgroundColor: theme.neutralBgTerciary},
            ]}>
            <Button
              text={t('service_management.page_selector', {
                page: page + 1,
                total: pageCount,
              })}
              IconRight={IconChevronDown}
              size="sm"
              variant="secondary"
              onPress={pageModal.onOpenModal}
            />
          </View>
        )}
        <ReactNativeZoomableView
          minZoom={1}
          maxZoom={3}
          bindToBorders
          style={[styles.pdfContainer, {backgroundColor: theme.neutralBg}]}>
          <View onLayout={onContainerLayout} style={styles.layoutContainer}>
            <View pointerEvents="none">
              <Pdf
                singlePage
                source={{uri}}
                page={page + 1}
                minScale={1}
                scale={1}
                spacing={0}
                fitPolicy={0}
                style={{
                  width: windowDimensions.width,
                  height: pages[page].height * mapping.baseScale,
                  backgroundColor: theme.neutralBg,
                }}
              />
            </View>
          </View>
          <View
            style={[
              styles.inputContainer,
              {width: containerLayout?.width, height: containerLayout?.height},
            ]}>
            {containerLayout && mapping.baseScale > 0
              ? components.map(component => renderInput(component))
              : null}
          </View>
        </ReactNativeZoomableView>
        <BottomModalFooter
          footer={{
            primaryButton: {
              onPress: onPressButton,
              text: t(
                page === pageCount - 1 ? 'general.send' : 'general.continue',
              ),
              disabled: disableSendButton,
              isLoading: isLoading,
            },
          }}
        />
      </View>
      <Menu
        data={pages}
        renderItem={renderPageItem}
        isVisible={pageModal.isVisible}
        onClose={pageModal.onCloseModal}
        title={t('service_management.pages')}
        snapPoints={['40%']}
      />
      {description && (
        <Dialog
          isVisible={infoModal.isVisible}
          onClose={infoModal.onCloseModal}
          title={t('service_management.description')}>
          <FormDescription
            body={description}
            richDescription={richDescription}
            withTitle={false}
          />
        </Dialog>
      )}
    </PdfFontScaleProvider>
  );
}

export default PdfFormContainer;
