import { FC, useEffect, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { useQuery, useInfiniteQuery, useQueryClient } from 'react-query';
import {
  useParams,
  Outlet,
  useNavigate,
  matchPath,
  useLocation,
} from 'react-router-dom';

import { useDebounce } from '@material-hu/hooks/useDebounce';
import ExpandIcon from '@material-hu/icons/material/ExpandMore';
import Box from '@material-hu/mui/Box';
import IconButton from '@material-hu/mui/IconButton';
import Menu from '@material-hu/mui/Menu';
import MenuItem from '@material-hu/mui/MenuItem';
import { useTheme } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';
import useMediaQuery from '@material-hu/mui/useMediaQuery';

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

import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useAuth } from 'src/contexts/JWTContext';
import { useSocket } from 'src/contexts/SocketContext';
import useGeneralError from 'src/hooks/useGeneralError';
import {
  getStatsForms,
  getUnassignedForms,
  getPendingForms,
  getClosedForms,
} from 'src/services/forms';
import { ChatStatus } from 'src/types/chats';
import { FormType } from 'src/types/forms';
import { canAddMessage, addLastMessageChat } from 'src/utils/chats';
import { formatTitle } from 'src/utils/helmetUtils';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getNextPage, getListLength } from 'src/utils/pagination';

import Badge from 'src/components/Badge';
import ChatsSidebar from 'src/components/dashboard/chat/ChatsSidebar';
import FormRequestList from 'src/components/dashboard/form/FormRequestList';
import {
  formKeys,
  deleteUnassignedForm,
  checkAssignFormToAgent,
  setFormMessageListData,
  setFormData,
  removeFormChatNotification,
} from 'src/components/dashboard/form/queries';
import {
  formRoutes,
  formSkeletonRoutes,
} from 'src/components/dashboard/form/routes';
import Tabs from 'src/components/tabs';

import { useMassiveAssign } from './MassiveAssignContext';

const FORM_PATH = formSkeletonRoutes.requests.detail(FormType.FORM);

const FormsRequests: FC = () => {
  const { t } = useLokaliseTranslation('forms');
  const queryClient = useQueryClient();
  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
  const open = Boolean(anchorEl);

  const { isSelecting, setIsSelecting, resetSelection } = useMassiveAssign();

  const { enqueueSnackbar } = useSnackbar();
  const showGeneralError = useGeneralError();
  const navigate = useNavigate();
  const socket = useSocket();
  const { user } = useAuth();
  const { id } = useParams();
  const { search } = useLocation();

  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down('sm'));

  const [formsQuery, setFormsQuery] = useState<string>('');
  const handleSearchForm = value => setFormsQuery(value);

  const query = useDebounce(formsQuery) || undefined;

  const redBubblesAgentForms = useQuery(
    formKeys.redBubblesAgent(),
    () => getStatsForms(user.id),
    {
      onError: err => showGeneralError(err, t('ERROR_GET_STATS_FORMS')),
    },
  );

  const unassignedFormsRedBubble =
    redBubblesAgentForms?.data?.data?.unassignedForms;
  const unreadAssignedFormsRedBubble =
    redBubblesAgentForms?.data?.data?.unreadAssignedFormChatMessages;

  const unassignedFormData = useInfiniteQuery(
    formKeys.unassignedForms(query),
    ({ pageParam = 1 }) => getUnassignedForms(query, pageParam),
    {
      getNextPageParam: (lastPage, pages) =>
        getNextPage(getListLength(pages), 20, pages),
      onError: err => showGeneralError(err, t('ERROR_GET_FORMS_UNASSIGNED')),
    },
  );

  const pendingFormData = useInfiniteQuery(
    formKeys.assignedForms(query),
    ({ pageParam = 1 }) => getPendingForms(query, pageParam),
    {
      getNextPageParam: (lastPage, pages) =>
        getNextPage(getListLength(pages), 20, pages),
      onError: err => showGeneralError(err, t('ERROR_GET_FORMS_PENDING')),
    },
  );

  const closedFormData = useInfiniteQuery(
    formKeys.closedForms(query),
    ({ pageParam = 1 }) => getClosedForms(query, pageParam),
    {
      getNextPageParam: (lastPage, pages) =>
        getNextPage(getListLength(pages), 20, pages),
      onError: err => showGeneralError(err, t('ERROR_GET_FORMS_CLOSED')),
    },
  );

  useEffect(() => {
    const clearUnreadMessages = () => {
      setFormData(Number(id), formItem => {
        if (formItem.unreadMessages > 0) {
          formItem.unreadMessages = 0;
          removeFormChatNotification();
          queryClient.invalidateQueries(formKeys.redBubblesAgent());
        }
        return formItem;
      });
    };

    clearUnreadMessages();
  }, [id]);

  useEffect(() => {
    const addMessage = formItem => {
      if (formItem.chat.id === Number(id)) {
        setFormMessageListData(
          Number(id),
          oldData => {
            if (!oldData) return oldData;

            if (canAddMessage(formItem, oldData.items)) {
              oldData.items = addLastMessageChat(oldData.items, formItem);
            }

            return oldData;
          },
          0,
        );
      }
    };

    const deleteUnassignedFormWrap = () => deleteUnassignedForm();

    const checkAssignFormToAgentWrap = data =>
      checkAssignFormToAgent(
        data.formId,
        data.responsibleItemIds,
        data.responsibleUserIds,
        user.id,
        () =>
          enqueueSnackbar({
            title: t('ERROR_UPDATE_FORM_AGENT'),
            variant: 'error',
          }),
      );

    const newFormChatCreated = () => {
      unassignedFormData.refetch();
      redBubblesAgentForms.refetch();
    };

    const refetchForms = () => {
      unassignedFormData.refetch();
      pendingFormData.refetch();
      closedFormData.refetch();
      redBubblesAgentForms.refetch();
      queryClient.invalidateQueries(formKeys.notifications.module());
    };

    socket.listenEvent(EVENTS_SOCKETS.BULK_ASSIGNMENT_OF_FORMS, refetchForms);

    socket.listenEvent(EVENTS_SOCKETS.BULK_FORM_REVIEW, refetchForms);

    socket.listenEvent(
      EVENTS_SOCKETS.NEW_FORM_CHAT_CREATED,
      newFormChatCreated,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.DELETE_UNASSIGNED_FORM_CHAT,
      deleteUnassignedFormWrap,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.FORM_APPROVAL_STEP_ASSIGNED,
      deleteUnassignedFormWrap,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.APPROVAL_FORM_TRANSITIONED,
      checkAssignFormToAgentWrap,
    );

    socket.listenEvent(EVENTS_SOCKETS.NEW_FORM_CHAT_MESSAGE_AGENT, addMessage);

    return () => {
      socket.closeEvent(EVENTS_SOCKETS.BULK_ASSIGNMENT_OF_FORMS, refetchForms);

      socket.closeEvent(EVENTS_SOCKETS.BULK_FORM_REVIEW, refetchForms);

      socket.closeEvent(
        EVENTS_SOCKETS.NEW_FORM_CHAT_CREATED,
        newFormChatCreated,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.DELETE_UNASSIGNED_FORM_CHAT,
        deleteUnassignedFormWrap,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.FORM_APPROVAL_STEP_ASSIGNED,
        deleteUnassignedFormWrap,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.APPROVAL_FORM_TRANSITIONED,
        checkAssignFormToAgentWrap,
      );

      socket.closeEvent(EVENTS_SOCKETS.NEW_FORM_CHAT_MESSAGE_AGENT, addMessage);
    };
  }, [socket, user.id, enqueueSnackbar, t]);

  const handleCancel = () => navigate(formRoutes.forms(FormType.FORM));

  const isFormPage = !!matchPath(
    {
      path: FORM_PATH,
      end: false,
    },
    location.pathname,
  );

  const isFormThread =
    isFormPage || location.pathname.includes('approval-workflow');

  const hideSidebar = isMobile && isFormThread;

  const showChat = !isMobile || isFormThread;

  const openMenu = event => setAnchorEl(event.currentTarget);
  const closeMenu = () => setAnchorEl(null);

  const handleClick = () => {
    setIsSelecting(true);
    closeMenu();
  };

  const tabs = [
    {
      id: t('UNASSIGNED'),
      title: (
        <>
          <Box sx={{ whiteSpace: 'nowrap' }}>{t('UNASSIGNED')}</Box>
          <Badge
            style={{ fontSize: '1em' }}
            count={unassignedFormsRedBubble}
            limit={100}
          />
        </>
      ),
      content: (
        <FormRequestList
          isBulkAssign
          formsQuery={formsQuery}
          handleSearchForm={handleSearchForm}
          {...unassignedFormData}
        />
      ),
      routeParam: ChatStatus.UNASSIGNED.toLowerCase(),
    },
    {
      id: t('ASSIGNED_TAB'),
      title: (
        <>
          <Box sx={{ whiteSpace: 'nowrap' }}>{t('ASSIGNED_TAB')}</Box>
          <Badge count={unreadAssignedFormsRedBubble} />
        </>
      ),
      content: (
        <FormRequestList
          formsQuery={formsQuery}
          handleSearchForm={handleSearchForm}
          {...pendingFormData}
        />
      ),
      routeParam: ChatStatus.ASSIGNED.toLowerCase(),
    },
    {
      id: t('CLOSED_TAB'),
      title: t('CLOSED_TAB'),
      content: (
        <FormRequestList
          formsQuery={formsQuery}
          handleSearchForm={handleSearchForm}
          {...closedFormData}
        />
      ),
      routeParam: ChatStatus.CLOSED.toLowerCase(),
    },
  ];

  const renderTools = () => (
    <Box>
      <IconButton
        id="toolbar-menu-button"
        aria-label={t('CHAT_MENU')}
        aria-controls="toolbar-menu"
        aria-expanded={open ? 'true' : undefined}
        aria-haspopup="true"
        onClick={openMenu}
      >
        <ExpandIcon />
      </IconButton>
      <Menu
        id="toolbar-menu"
        MenuListProps={{
          'aria-labelledby': 'toolbar-menu-button',
        }}
        anchorEl={anchorEl}
        open={open}
        onClose={closeMenu}
      >
        <MenuItem
          onClick={handleClick}
          disabled={isSelecting || search.includes('closed=true')}
        >
          <Typography
            sx={{
              display: 'flex',
              alignItems: 'center',
            }}
          >
            {t('SELECT_MULTIPLE')}
          </Typography>
        </MenuItem>
      </Menu>
    </Box>
  );

  return (
    <>
      <Helmet>
        <title>{formatTitle(t('REQUESTS'))}</title>
      </Helmet>
      <Box
        sx={{
          backgroundColor: 'background.default',
          height: '100%',
          display: 'flex',
        }}
      >
        <>
          <Box
            sx={{
              display: 'flex',
              flex: 1,
              width: '100%',
            }}
          >
            <ChatsSidebar
              title={t('REQUESTS')}
              hide={hideSidebar}
              onlyTitle
              withMassiveApprove
              onBackClick={handleCancel}
              actions={renderTools()}
            >
              <Tabs
                id="requests"
                tabs={tabs}
                withRouteParams
                onTabChange={resetSelection}
                tabsProps={{
                  variant: 'fullWidth',
                }}
                tabProps={{
                  wrapped: true,
                  sx: {
                    minWidth: '0px !important',
                  },
                }}
                tabPanelProps={{
                  withScrollbar: true,
                  options: { suppressScrollX: true },
                }}
              />
            </ChatsSidebar>
            {showChat && <Outlet />}
          </Box>
        </>
      </Box>
    </>
  );
};

export default FormsRequests;
