import {useCallback, useMemo, useState} from 'react';
import {View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {CommonActions} from '@react-navigation/native';
import {useMutation, useQueryClient} from '@tanstack/react-query';
import Pdf from 'react-native-pdf';
import {
  Button,
  DigitalSignatureDialog,
  PdfLoadingIndicator,
  Spinner,
} from '@components';
import {getApiHeaders} from '@config/api';
import {tokenManager} from '@config/tokens';
import {trackCustomHumandError} from '@hooks/useGeneralError';
import {Navigation} from '@interfaces/navigation';
import {DOCUMENT_QUERY_KEYS} from '@modules/documents/constants';
import {DocumentsAmplitudeSource} from '@modules/documents/interfaces';
import {signDocument} from '@modules/documents/services';
import {useAskForPassword} from '@modules/documents/hooks';
import {useInstanceId} from '@redux/selectors';
import {showSnackbar} from '@redux/dispatchers';
import {uploadDigitalSignature} from '@services/multimedia';
import {fetchModulesNotifications, logAmplitudeEvent} from '@shared/utils';
import {
  AMPLITUDE_EVENTS,
  SECURE_FILES_PATH,
  Screens,
  WILL_DER_INSTANCE_ID,
} from '@shared/constants';
import {ERROR} from '@shared/strings';
import {ModulesNotifications} from '@shared/notifications';
import {useTheme} from '@shared/theme';

import {styles} from './styles';

function SignDocument({
  route: {
    params: {file},
  },
  navigation,
}: Navigation<Screens.SIGN_DOCUMENT>) {
  const {t} = useTranslation();
  const {theme} = useTheme();
  const queryClient = useQueryClient();
  const {PasswordDialog, askForPassword} = useAskForPassword();
  const [signatureDialog, setSignatureDialog] =
    useState<Nullable<{compliant: boolean}>>(null);
  const [isLoading, setIsLoading] = useState(false);
  const instanceId = useInstanceId();
  const isWillDerInstance = instanceId === WILL_DER_INSTANCE_ID;
  const token = tokenManager.getAccessToken();

  const source = useMemo(
    () =>
      file.source.includes(SECURE_FILES_PATH)
        ? {
            uri: encodeURI(file.source),
            headers: getApiHeaders(token),
            cache: false,
          }
        : {uri: file.source, cache: false},
    [file.source, token],
  );

  const signDocumentMutation = useMutation({
    mutationFn: signDocument,
    onSuccess: (_data, {inDisagreement}) => {
      logAmplitudeEvent(AMPLITUDE_EVENTS.DOCUMENT_SIGN, {
        fileId: file.id,
        folderId: file.folderId,
        inDisagreement: file.allowDisagreement ? inDisagreement : null,
      });
      queryClient.resetQueries({queryKey: DOCUMENT_QUERY_KEYS.documentFolders});
      queryClient.resetQueries({
        queryKey: DOCUMENT_QUERY_KEYS.pendingDocuments,
      });
      queryClient.resetQueries({
        queryKey: DOCUMENT_QUERY_KEYS.allPendingDocuments,
      });
      queryClient.invalidateQueries({
        queryKey: DOCUMENT_QUERY_KEYS.documentsByFolder(file.folderId),
      });
      fetchModulesNotifications([ModulesNotifications.DOCUMENT]);
      showSnackbar({
        title: t('documents.sign_success_title'),
        description: t('documents.sign_success_description', {name: file.name}),
        variant: 'success',
      });
      navigation.dispatch(
        CommonActions.navigate({
          name: Screens.DOCUMENTS,
          params: {
            source: DocumentsAmplitudeSource.APPS,
          },
          merge: true,
          pop: true,
        }),
      );
    },
    onSettled: () => setIsLoading(false),
  });

  const acceptAction = async (signature: string, isCompliant: boolean) => {
    setIsLoading(true);
    const signatureUrl = await uploadDigitalSignature(signature);
    if (signatureUrl === ERROR) {
      setIsLoading(false);
      return;
    } else {
      signDocumentMutation.mutate({
        id: file.id,
        signatureUrl,
        inDisagreement: !isCompliant,
      });
    }
  };

  const onAccept = (signature: string) => {
    const isCompliant = !!signatureDialog?.compliant;
    setSignatureDialog(null);
    !isLoading && askForPassword(() => acceptAction(signature, isCompliant));
  };

  const onSign = () => setSignatureDialog({compliant: true});
  const onSignNotCompliant = () => setSignatureDialog({compliant: false});
  const onCancel = () => setSignatureDialog(null);

  const onPdfError = (error: object) => {
    trackCustomHumandError(error, 'SignPdfError');
  };

  const renderPdfLoader = useCallback(
    (progress: number) => <PdfLoadingIndicator progress={progress} />,
    [],
  );

  return (
    <>
      <View style={styles.container}>
        <Pdf
          showsHorizontalScrollIndicator={false}
          source={source}
          onError={onPdfError}
          renderActivityIndicator={renderPdfLoader}
          trustAllCerts={false}
          style={[
            styles.pdf,
            {backgroundColor: theme.background.layout.default},
          ]}
        />
        <View
          style={[
            styles.bottomContainer,
            {
              backgroundColor: theme.background.layout.tertiary,
              borderColor: theme.border.neutral.default,
            },
            file.allowDisagreement && styles.bigContainer,
          ]}>
          {isLoading ? (
            <View style={styles.spinner}>
              <Spinner />
            </View>
          ) : (
            <>
              <Button
                text={t('documents.sign_document')}
                onPress={onSign}
                // TODO: Remove this line after testing
                variant={isWillDerInstance ? 'secondary' : 'primary'}
              />
              {file.allowDisagreement && (
                <Button
                  text={t('documents.sign_document_disagreement')}
                  onPress={onSignNotCompliant}
                  variant="secondary"
                />
              )}
            </>
          )}
        </View>
      </View>
      <DigitalSignatureDialog
        isVisible={!!signatureDialog}
        onCloseDialog={onCancel}
        title={t('documents.sign_document')}
        acceptText={
          signatureDialog && !signatureDialog.compliant
            ? t('documents.sign_document_disagreement')
            : undefined
        }
        onAccept={onAccept}
        isLoading={isLoading}
      />
      {PasswordDialog}
    </>
  );
}

export default SignDocument;
