import { ReactNode, useEffect, useState } from 'react';
import { QueryKey, useMutation, useQuery, useQueryClient } from 'react-query';

import { AxiosResponse } from 'axios';
import { useDrawer } from '@material-hu/hooks/useDrawer';
import { useModal } from '@material-hu/hooks/useModal';
import Container from '@material-hu/mui/Container';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import HuAlert from '@material-hu/components/design-system/Alert';
import Button from '@material-hu/components/design-system/Buttons/Button';
import HuDialog from '@material-hu/components/design-system/Dialog';
import HuCircularProgress from '@material-hu/components/design-system/ProgressIndicators/Spinner';

import useGeneralError from 'src/hooks/useGeneralError';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import { Criteria } from 'src/types/audience';
import { User } from 'src/types/user';
import { ConditionsCriteria } from 'src/types/vacations';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { PaginatedResponse, Pagination } from 'src/utils/tableUtils';

import CriteriasContainer from '../CriteriasContainer';
import { useCriteria } from '../criteriaContext';
import { Module } from '../module';
import SeeCollaborators from '../SeeCollaborators';
import { formatConditionsCriteria } from '../utils';

import useAllUsersConfirmationModal from './useAllUsersConfirmationModal';

export type SegmentationCriteriaService = {
  createResourceTemplate: (
    resourceId: number,
  ) => Promise<AxiosResponse<{ id: number }>>;
  getResourceCriteria?: (groupId: number) => Promise<AxiosResponse<any>>;
  getResourceTemplateCriteria: (
    templateId: number,
  ) => Promise<AxiosResponse<any>>;
  getResourceTemplateUsers: (
    templateId: number,
    pagination: Pagination,
  ) => Promise<AxiosResponse<PaginatedResponse<User>>>;
  updateTemplateCriteria: (
    templateId: number,
    criteria: Criteria[],
  ) => Promise<AxiosResponse<any>>;
  deleteResourceTemplate: (templateId: number) => Promise<AxiosResponse<any>>;
  updateResourceCriteria: (
    resourceId: number,
    templateId: number,
    criteria: any,
    conditions?: ConditionsCriteria[],
  ) => Promise<AxiosResponse<any>>;
  customGetIndividualCriteriaUsers?: (
    pagination: Pagination,
    templateId: number,
  ) => Promise<AxiosResponse<PaginatedResponse<User>, any>>;
};

export type QueryKeys = {
  resourceTemplateCriteria: (
    resourceId: number,
    resourceTemplateId: number,
  ) => (string | number)[];
  resourceTemplateUsers: (
    resourceId: number,
    resourceTemplateId: number,
  ) => (string | number)[];
  customKeyIndividualCriteriaUsers?: (
    resourceId: number,
    resourceTemplateId: number,
  ) => (string | number)[];
};

type Props = {
  resourceId: number;
  service: SegmentationCriteriaService;
  queryKeys: QueryKeys;
  behaviourSettings?: {
    allowsMultipleSegmentedCriteria: boolean;
    skipAllCollaboratorsDrawer: boolean;
  };
  goBack: () => void;
  onCreateResourceTemplateError?: (error: any) => void;
  onUpdateResourceCriteriaError?: (error: any) => void;
  onCriteriaSelectedChange?: (criteriaSelected: Criteria[]) => void;
  blockingErrorComponent?: ReactNode;
  saveErrorComponent?: ReactNode;
  templateCreated?: boolean;
  module?: Module;
};

const useSegmentationCriteria = ({
  resourceId,
  service,
  queryKeys,
  behaviourSettings = {
    allowsMultipleSegmentedCriteria: true,
    skipAllCollaboratorsDrawer: false,
  },
  goBack,
  onCreateResourceTemplateError,
  onUpdateResourceCriteriaError,
  onCriteriaSelectedChange,
  blockingErrorComponent,
  saveErrorComponent,
  templateCreated = true,
  module = Module.TIME_OFF,
}: Props) => {
  const excludeDeactivatedUsersFromCollaboratorQueries =
    module === Module.GROUPS;
  const {
    criteriaSelected,
    setCriteriaSelected,
    setTemplateId,
    criteriaSelectedDirty,
  } = useCriteria();
  const { t } = useLokaliseTranslation(['audience']);
  const showGeneralError = useGeneralError();
  const [templateWasCreated, setTemplateWasCreated] = useState(false);
  const queryClient = useQueryClient();
  const HuGoThemeProvider = useHuGoTheme();

  const {
    data: { templateId } = { templateId: undefined },
    isLoading: templateIdIsLoading,
  } = useQuery(
    queryKeys.resourceTemplateCriteria(resourceId, 1),
    async () => {
      try {
        const {
          data: { id: newTemplateId },
        } = await service.createResourceTemplate(resourceId);
        let criteria = [];
        if (templateCreated) {
          const { data: templateCriteria } =
            await service.getResourceTemplateCriteria(newTemplateId);
          criteria = templateCriteria.items;
        } else {
          if (service.getResourceCriteria) {
            const { data: currentCriteria } =
              await service.getResourceCriteria(resourceId);
            criteria = currentCriteria.items;
          }
        }
        setTemplateId(newTemplateId);
        setCriteriaSelected(criteria, false);
        return { templateId: newTemplateId };
      } catch (error) {
        (onCreateResourceTemplateError ?? showGeneralError)(error);
        return { templateId: undefined };
      }
    },
    {
      keepPreviousData: true,
      onError: err => (onCreateResourceTemplateError ?? showGeneralError)(err),
    },
  );

  const { isLoading: isLoadingTemplateCriteria } = useQuery(
    queryKeys.resourceTemplateCriteria(resourceId, templateId!),
    async () => service.getResourceTemplateCriteria(templateId!),
    {
      enabled: !!templateId && templateCreated,
      onSuccess: ({ data }) => setCriteriaSelected(data.items, false),
    },
  );

  const {
    data: totalCount = 0,
    isLoading: isLoadingTotalCount,
    isFetching: isFetchingTotalCount,
  } = useQuery(
    queryKeys.resourceTemplateUsers(resourceId, templateId!),
    () =>
      service.getResourceTemplateUsers(templateId!, {
        page: 0,
        limit: 1,
      }),
    {
      select: r => r.data.count,
      enabled: !!templateId && templateCreated,
    },
  );

  const { mutateAsync, isLoading: isLoadingTemplateMutation } = useMutation(
    () => service.updateTemplateCriteria(templateId!, criteriaSelected),
    {
      onSuccess: () => {
        setTemplateWasCreated(true);
        queryClient.resetQueries(
          queryKeys.resourceTemplateUsers(resourceId, templateId!),
        );
      },
    },
  );

  // criteriaSelectedDirty is used to stop updateTemplateMutation from running on mount and causing a race condition on the backend
  useEffect(() => {
    if (templateId && criteriaSelectedDirty) {
      mutateAsync();
      onCriteriaSelectedChange?.(criteriaSelected);
    }
  }, [criteriaSelected]);

  useEffect(
    () => () => {
      if (templateId) {
        service.deleteResourceTemplate(templateId);
        queryClient.removeQueries(
          queryKeys.resourceTemplateCriteria(resourceId, 1),
        );
        queryClient.removeQueries(
          queryKeys.resourceTemplateCriteria(resourceId, templateId),
        );
      }
    },
    [templateId],
  );

  const {
    showDrawer: showTotalCollaboratorsDrawer,
    drawer: totalCollaboratorsDrawer,
  } = useDrawer(
    SeeCollaborators,
    {
      title: t('selected_collaborators'),
      footer: (
        <HuAlert
          title={t('selected_collaborators_count', {
            count: totalCount,
          })}
          severity="info"
        />
      ),
    },
    {
      service: pagination =>
        service.getResourceTemplateUsers(templateId!, pagination),
      queryKey: queryKeys.resourceTemplateUsers(
        resourceId,
        templateId!,
      ) as QueryKey[],
      title: t('total_audience_title'),
    },
  );

  const {
    modal: exitModal,
    showModal: showExitModal,
    closeModal: closeExitModal,
  } = useModal(
    () => (
      <HuDialog
        title={
          criteriaSelected.length > 0
            ? t('without_changes_title')
            : t('without_collaborator_title')
        }
        textBody={
          criteriaSelected.length > 0
            ? t('without_changes_description')
            : t('without_collaborator_description')
        }
        primaryButtonProps={{
          children: t('quit'),
          onClick: () => goBack(),
        }}
        secondaryButtonProps={{
          children: t('general:cancel'),
          onClick: closeExitModal,
        }}
        onClose={closeExitModal}
      />
    ),
    { fullWidth: true, maxWidth: 'sm' },
  );

  const {
    modal: allUsersConfirmationModal,
    showModal: showAllUsersConfirmationModal,
  } = useAllUsersConfirmationModal(undefined, {
    excludeDeactivatedUsers: excludeDeactivatedUsersFromCollaboratorQueries,
  });

  const updateResourceMutation = useMutation(
    () => {
      let conditions = undefined;
      if (module === Module.TIME_OFF) {
        conditions = formatConditionsCriteria(criteriaSelected);
      }
      return service.updateResourceCriteria(
        resourceId,
        templateId!,
        criteriaSelected,
        conditions,
      );
    },
    {
      onSuccess: () => goBack(),
      onError: err => (onUpdateResourceCriteriaError ?? showGeneralError)(err),
    },
  );

  const hasCriteria = criteriaSelected.length > 0;
  const isLoadingOrFetchingTotalCount =
    isLoadingTotalCount || isFetchingTotalCount;

  const disabled =
    isLoadingOrFetchingTotalCount ||
    isLoadingTemplateMutation ||
    isLoadingTemplateCriteria;

  const disabledSave = disabled || !templateWasCreated;

  const exitOfAssignPeopleView = () => {
    if (templateWasCreated) {
      showExitModal();
      return;
    }
    goBack();
  };

  return {
    exitOfAssignPeopleView,
    save: () => updateResourceMutation.mutate(),
    isLoading: updateResourceMutation.isLoading,
    disabledSave,
    templateId,
    component: (
      <HuGoThemeProvider>
        {exitModal}
        {totalCollaboratorsDrawer}
        {allUsersConfirmationModal}
        {templateIdIsLoading ? (
          <Stack sx={{ flex: 1 }}>
            <HuCircularProgress
              centered
              sx={{ mt: 3 }}
            />
          </Stack>
        ) : (
          <Stack
            sx={{
              width: '100%',
              px: 2,
              flex: 1,
              overflow: 'auto',
              alignItems: 'center',
            }}
          >
            <Container maxWidth="md">
              <Stack
                sx={{
                  mt: 5,
                  flexDirection: 'row',
                  alignItems: 'center',
                  justifyContent: 'space-between',
                }}
              >
                <Stack>
                  <Typography
                    variant="globalL"
                    fontWeight="fontWeightSemiBold"
                  >
                    {t(
                      hasCriteria ? 'collaborators' : 'add_new_criteria_title',
                    )}
                  </Typography>
                  <Typography variant="globalS">
                    {t(
                      hasCriteria
                        ? 'select_collaborator'
                        : 'add_new_criteria_description',
                      { context: module },
                    )}
                  </Typography>
                </Stack>
                {hasCriteria && (
                  <Button
                    variant="secondary"
                    onClick={() => showTotalCollaboratorsDrawer()}
                    loading={disabled}
                  >
                    {t('total_audience', {
                      count: totalCount,
                    })}
                  </Button>
                )}
              </Stack>
              {blockingErrorComponent}
              {!blockingErrorComponent && (
                <CriteriasContainer
                  isLoadingTemplate={isLoadingTemplateMutation}
                  hasCriteria={hasCriteria}
                  service={service}
                  queryKeys={queryKeys}
                  saveErrorComponent={saveErrorComponent}
                  criteriasSelected={criteriaSelected}
                  behaviourSettings={behaviourSettings}
                  showAllUsersConfirmationModal={showAllUsersConfirmationModal}
                  excludeDeactivatedUsersFromCollaboratorQueries={
                    excludeDeactivatedUsersFromCollaboratorQueries
                  }
                />
              )}
            </Container>
          </Stack>
        )}
      </HuGoThemeProvider>
    ),
  };
};

export default useSegmentationCriteria;
