import React, { useEffect, useRef, useState } from 'react';
import { NetworkStatus } from '@apollo/client';
import { Box, HistoryDisplay, ListBase, Text } from '@nova-hf/ui';
import { ErrorBanner } from 'beta/components/error/ErrorBanner';
import UI from 'beta/store/ui';
import { IContext } from 'beta/typings/context';
import { formatDate } from 'beta/utils/helpers';
import { useTranslation } from 'beta/utils/i18n';
import { inject, observer } from 'mobx-react';
import { useRouter } from 'next/router';
import {
  ChannelType,
  DeliveryStatus,
  Maybe,
  NotificationCategory,
  RegardingType,
  useNotificationDetailsLazyQuery,
  useNotificationsQuery,
} from 'typings/graphql';

type HistoryProps = {
  ui?: UI;
  regardingIds?: Array<string>;
  recipientId?: string;
  phoneNumber?: string;
  category?: NotificationCategory;
};

const History = ({ ui, regardingIds, recipientId, phoneNumber, category }: HistoryProps) => {
  const router = useRouter();
  const { t } = useTranslation(['service', 'errors']);
  const customerId = router?.query?.customerId ?? '';
  const [page, setPage] = useState(1);
  const lastFetchedPageRef = useRef(0);
  const [showDeliveries, setShowDeliveries] = useState(true);
  const [deliveryDetails, setDeliveryDetails] = React.useState<Record<string, string>>({});

  const { data, error, loading, networkStatus, refetch, fetchMore } = useNotificationsQuery({
    variables: {
      input: {
        regardingIds: regardingIds ?? [],
        recipientId: recipientId ?? '',
        phoneNumber: phoneNumber ?? '',
        page: page,
        perPage: 50,
        ...(category?.toString() !== 'All' && category ? { category } : {}),
      },
    },
    skip: !regardingIds && !recipientId && !phoneNumber,
  });

  const [getDetails] = useNotificationDetailsLazyQuery();

  const handleNotificationOpen = async (notificationId: string) => {
    if (notificationId) {
      const notification = data?.notifications?.notifications?.find(
        (n) => n?.id === notificationId,
      );

      if (notification?.deliveries) {
        for (const delivery of notification.deliveries) {
          if (delivery?.channelType === ChannelType.Email && !deliveryDetails[delivery.id]) {
            const result = await getDetails({
              variables: {
                input: {
                  deliveryId: delivery.id,
                  notificationId: notification.id,
                },
              },
            });

            const htmlBody = result?.data?.notificationDetails?.htmlBody;
            if (htmlBody) {
              setDeliveryDetails((prevDetails) => ({
                ...prevDetails,
                [delivery.id]: htmlBody,
              }));
            }
          }
        }
      }
    }
  };

  const channelTypeMap = (type?: Maybe<ChannelType>) => {
    switch (type) {
      case ChannelType.Application:
        return {
          title: t('history.sentNotification'),
          message: t('history.notificationSent'),
          icon: 'novaLogo',
        };
      case ChannelType.Email:
        return { title: t('history.emailSent'), message: t('history.emailSentTo'), icon: 'letter' };
      case ChannelType.TextMessage:
        return { title: t('history.smsSent'), message: t('history.smsSentTo'), icon: 'phoneHeart' };
      default:
        return {
          title: t('history.sentNotification'),
          message: t('history.notificationSent'),
          icon: 'novaLogo',
        };
    }
  };

  const notificationTypeMap = (type?: Maybe<RegardingType>) => {
    switch (type) {
      case RegardingType.Customer:
        return { name: t('history.customer'), icon: 'profile' };
      case RegardingType.Service:
        return { name: t('history.service'), icon: 'zap' };
      case RegardingType.Contract:
        return { name: t('history.contract'), icon: 'info' };
      case RegardingType.Order:
        return { name: t('history.order'), icon: 'receipt' };
      default:
        return { name: t('history.message'), icon: 'novaLogo' };
    }
  };
  const notifications = data?.notifications?.notifications;
  const [usedNotifications, setUsedNotifications] = useState([]);
  const mappedNotifications = notifications
    ?.map((notification) => {
      const deliveries = notification?.deliveries;
      const notificationTypeInfo = notificationTypeMap(notification?.regardingType);
      const mappedDeliveries = deliveries
        ?.map((delivery) => {
          if (delivery?.created) {
            const channelTypeInfo = channelTypeMap(delivery?.channelType);
            return {
              id: delivery.id,
              time: formatDate(delivery?.created, 'dd.MM.yyyy - HH:mm'),
              title: channelTypeInfo?.title,
              icon: channelTypeInfo?.icon,
              message: `${channelTypeInfo.message} ${delivery?.sentTo}.`,
              result: {
                result:
                  delivery?.status === DeliveryStatus.Delivered
                    ? t('history.deliverySuccess')
                    : t('history.deliveryFailure'),
                resultMessage:
                  delivery?.status === DeliveryStatus.Delivered
                    ? undefined
                    : delivery?.resultMessage,
                resultReason: t('history.reason'),
                resultColor: delivery?.status === DeliveryStatus.Delivered ? 'success' : 'warning',
              },
            };
          } else {
            return null;
          }
        })
        .filter(Boolean);
      return {
        deliveries: mappedDeliveries,
        name: notification?.subject,
        time: notification?.created ? formatDate(notification?.created, 'dd.MM.yyyy - HH:mm') : '',
        regardingType: notificationTypeInfo.name,
        icon: notificationTypeInfo.icon,
        title: notification?.subject,
        message: notification?.message,
        id: notification?.id,
      };
    })
    .filter((notification) => notification != null);
  useEffect(() => {
    if (data && data.notifications && data.notifications.notifications) {
      setUsedNotifications((prevNotifications) => [...prevNotifications, ...mappedNotifications]);
    }
    let timeout: NodeJS.Timeout;
    const handleScroll = () => {
      clearTimeout(timeout);
      timeout = setTimeout(() => {
        const { scrollTop, clientHeight, scrollHeight } = document.documentElement || document.body;
        if (
          scrollTop + clientHeight + 500 >= scrollHeight &&
          !loading &&
          networkStatus !== NetworkStatus.fetchMore &&
          !(!notifications || notifications.length === 0)
        ) {
          setPage((prevPage) => {
            const nextPage = prevPage + 1;
            if (nextPage === lastFetchedPageRef.current) {
              return prevPage;
            }
            const fetchMoreVariables = {
              input: {
                recipientId: customerId.toString(),
                regardingIds: regardingIds ?? [],
                phoneNumber: phoneNumber ?? '',
                page: nextPage,
                perPage: 50,
                ...(category?.toString() !== 'All' && category ? { category } : {}),
              },
              skip: nextPage === lastFetchedPageRef.current,
            };

            fetchMore({ variables: fetchMoreVariables }).then(() => {
              lastFetchedPageRef.current = nextPage;
            });
            return nextPage;
          });
        }
      }, 200);
    };

    window.addEventListener('scroll', handleScroll);

    return () => {
      window.removeEventListener('scroll', handleScroll);
      clearTimeout(timeout);
    };
  }, [fetchMore, page, customerId, data]);

  useEffect(() => {
    setUsedNotifications(mappedNotifications ?? []);
    setPage(1);
  }, [category]);

  return (
    <Box marginBottom={5} width="100%">
      <Text variant="h6">{t('history.myHistory')}</Text>
      {error || loading ? (
        <Box marginTop={5}>
          <ErrorBanner
            eyebrowTexts={[
              t('errors:history.eyebrows.1'),
              t('errors:history.eyebrows.2'),
              t('errors:history.eyebrows.3'),
            ]}
            titles={[
              t('errors:history.titles.1'),
              t('errors:history.titles.2'),
              t('errors:history.titles.3'),
            ]}
            descriptions={[
              t('errors:history.descriptions.1'),
              t('errors:history.descriptions.2'),
              t('errors:history.descriptions.3'),
            ]}
            icon="zap"
            color={ui?.serviceColor ?? 'attention'}
            showLoading={loading || networkStatus === NetworkStatus.refetch}
            refetchButton={{
              text: t('errors:buttons.refresh'),
              icon: 'refresh',
              onClick: () => refetch(),
            }}
            loadingComponent={
              <>
                <ListBase isLoading gap={3} />
                <ListBase isLoading gap={3} />
                <ListBase isLoading />
              </>
            }
          />
        </Box>
      ) : (
        <Text>{!usedNotifications?.length ? 'Engin saga fannst...' : ''}</Text>
      )}
      {data && !!usedNotifications && !!usedNotifications.length && (
        <Box style={{ whiteSpace: 'pre-line' }} marginLeft={1}>
          <HistoryDisplay
            notifications={usedNotifications}
            color={ui?.serviceColor}
            shouldShowDeliveries={showDeliveries}
            deliveryDetails={deliveryDetails}
            onInfoClick={handleNotificationOpen}
            button={{
              icon: showDeliveries ? 'arrowUp' : 'arrowDown',
              text: showDeliveries ? t('history.showLess') : t('history.showMore'),
              colorScheme: ui?.serviceColor,
              onClick: () => setShowDeliveries((shouldShow) => !shouldShow),
            }}
          />
        </Box>
      )}
      {loading && <ListBase isLoading />}
    </Box>
  );
};

History.getInitialProps = ({ pathname }: IContext) => {
  return {
    pathname,
    namespacesRequired: ['service', 'errors'],
  };
};

export default inject('ui')(observer(History));
