import { useMemo, useRef } from 'react';
import { FormProvider } from 'react-hook-form';
import { useQuery } from 'react-query';
import { useOutletContext } from 'react-router-dom';

import { concat } from 'lodash-es';

import { useDebounce } from '@material-hu/hooks/useDebounce';
import { useHuPagination } from '@material-hu/hooks/useHuPagination';
import { PeopleExperience } from '@material-hu/components/composed-components/peopleExperience';
import * as PxTypes from '@material-hu/components/composed-components/peopleExperience/types';

import { useAuth } from 'src/contexts/JWTContext';
import useManagerParticipation from '../../../../../hooks/useManagerParticipation';
import { getBaseSegments } from '../../../../../constants';
import { pxKeys } from '../../../../../queries';
import { makeBlacklistSegmentChecker } from '../../../../../utils/segmentBlacklist';
import { formatAmount } from '../../../../../utils/formatting';
import { getSegmentationGroups } from '../../../../../services';
import {
  type ParticipationListParams,
  SegmentType,
  SortFilter,
} from '../../../../../types';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { type ManagerResultsOutletContext } from '../../../types';

import ParticipationList from './ParticipationList';

const { ParticipationDashboard: MHParticipationDashboard } = PeopleExperience;

const INITIAL_SORT_FILTER = SortFilter.ASC;

const getSegmentType = (type: PxTypes.SegmentationGroupType): SegmentType => {
  if (type === PxTypes.SegmentationGroupType.AGE) return SegmentType.AGE;
  if (type === PxTypes.SegmentationGroupType.SENIORITY)
    return SegmentType.SENIORITY;
  return SegmentType.SEGMENTATION_GROUPS;
};

const ParticipationDashboard = () => {
  const { survey } = useOutletContext<ManagerResultsOutletContext>();
  const { t } = useLokaliseTranslation('people_experience');
  const { instance } = useAuth();
  const surveyId = survey.id;
  const baseSegments = getBaseSegments(t);

  const segmentInitialised = useRef(false);

  const defaultSegment = baseSegments[0];
  const defaultFilters = useMemo(
    () => ({
      segmentId: String(defaultSegment.id),
      dimension: defaultSegment.type,
    }),
    [defaultSegment.id, defaultSegment.type],
  );

  const { params, form, setPartialParams, Pagination } = useHuPagination({
    defaultOrder: INITIAL_SORT_FILTER,
    defaultFilters,
  });

  const sortOrder = params.order as SortFilter;
  const searchQuery = params.search;
  const segmentType = (params.dimension as SegmentType) ?? SegmentType.BOSSES;

  const debouncedSearchQuery = useDebounce(params.search);

  const isSegmentBlacklisted = makeBlacklistSegmentChecker({
    instanceId: instance?.id,
    surveyId,
  });

  const { data: segments } = useQuery(
    pxKeys.segmentationGroups(surveyId),
    () => getSegmentationGroups({ surveyId, page: 0, limit: 100 }),
    {
      select: response => {
        const allSegments = concat(
          baseSegments,
          response.data.items.map(seg => ({
            id: seg.id,
            title: seg.name,
            type: getSegmentType(seg.type as PxTypes.SegmentationGroupType),
          })),
        );
        return allSegments.filter(seg => !isSegmentBlacklisted(seg.id));
      },
      onSuccess: responseData => {
        if (segmentInitialised.current) return;
        segmentInitialised.current = true;
        const urlSegmentExists = responseData.some(
          seg =>
            String(seg.id) === params.segmentId &&
            seg.type === params.dimension,
        );
        if (!urlSegmentExists && responseData[0]) {
          setPartialParams(
            {
              segmentId: String(responseData[0].id),
              dimension: responseData[0].type,
            },
            true,
          );
        }
      },
    },
  );

  const selectedSegment = (segments ?? baseSegments).find(
    seg => String(seg.id) === params.segmentId && seg.type === segmentType,
  );

  const initialParams: ParticipationListParams = {
    surveyId,
    depth: 0,
    parentId:
      segmentType === SegmentType.SEGMENTATION_GROUPS
        ? Number(params.segmentId)
        : null,
    limit: params.pagination.limit,
    page: params.pagination.page,
    dimension: segmentType,
    order: sortOrder,
    q: searchQuery ? debouncedSearchQuery : searchQuery,
  };

  const { data, isLoading, isPreviousData } =
    useManagerParticipation(initialParams);

  const showSortAndSearch = ![
    SegmentType.BOSSES,
    SegmentType.DIRECT_BOSS,
  ].includes(segmentType);

  return (
    <FormProvider {...form}>
      <MHParticipationDashboard
        segments={
          (segments ??
            baseSegments) as unknown as PxTypes.ParticipationSegmentFilter[]
        }
        selectedSegment={
          selectedSegment as unknown as
            | PxTypes.ParticipationSegmentFilter
            | undefined
        }
        onSegmentChange={seg =>
          setPartialParams(
            {
              segmentId: String(seg.id),
              dimension: seg.type,
              search: '',
              order: INITIAL_SORT_FILTER,
            },
            true,
          )
        }
        showSort={showSortAndSearch}
        sortOrder={sortOrder as unknown as PxTypes.SortFilter}
        onSortChange={order =>
          setPartialParams({ order: order as unknown as SortFilter }, true)
        }
        showSearch={showSortAndSearch}
        searchQuery={searchQuery}
        onSearchChange={value => setPartialParams({ search: value }, true)}
        items={data?.items}
        isLoading={isLoading}
        isPreviousData={isPreviousData}
        renderChildren={(item, isExpanded) =>
          item.hasChildren ? (
            <ParticipationList
              depth={1}
              surveyId={surveyId}
              parentId={
                segmentType === SegmentType.SEGMENTATION_GROUPS
                  ? Number(params.segmentId)
                  : item.id
              }
              page={1}
              order={sortOrder}
              dimension={segmentType}
              limit={item.childrenAmount}
              expanded={isExpanded}
            />
          ) : undefined
        }
        noDataMessage={t('NOT_ENOUGH_PARTICIPANTS')}
        emptyState={{
          title: t('NOT_ENOUGH_DATA_TITLE'),
          description: t('NOT_ENOUGH_DATA_DESCRIPTION'),
        }}
        formatRatioLabel={(completed, total) =>
          t('participation.ratio', {
            current: formatAmount(completed),
            total: formatAmount(total),
            count: total,
          })
        }
        paginationController={
          <Pagination
            inputProps={{
              type: 'changer',
              loading: isLoading,
              totalPages: data?.totalPages,
            }}
          />
        }
        labels={{
          showBy: t('SEGMENT'),
          ascending: t('general:ascending'),
          descending: t('general:descending'),
          searchPlaceholder: t('GENERAL:SEARCH'),
        }}
      />
    </FormProvider>
  );
};

export default ParticipationDashboard;
