import { useState, useMemo, useEffect, useRef } from 'react';
import { useFormContext } from 'react-hook-form';
import { useInfiniteQuery, useQuery } from 'react-query';

import Typography from '@material-hu/mui/Typography';

import { AxiosResponse } from 'axios';
import Stack from '@material-hu/mui/Stack';

import HuFormAutocomplete from '@material-hu/components/design-system/Inputs/Autocomplete/form';
import HuMenuItem from '@material-hu/components/design-system/Menu/components/MenuItem';
import HuSkeleton from '@material-hu/components/design-system/Skeleton';

import { serviceManagementKeys } from 'src/pages/dashboard/ServiceManagement/queries';
import {
  getAgentGroup,
  getAgentGroupsHydrated,
} from 'src/pages/dashboard/ServiceManagement/services';
import {
  AgentGroupHydrated,
  AgentGroupStatus,
} from 'src/pages/dashboard/ServiceManagement/types';
import { PaginatedResponse } from 'src/utils/tableUtils';

import { InfiniteListAutocomplete } from './InfiniteListAutocomplete';

type AxiosResponseAgents = AxiosResponse<PaginatedResponse<AgentGroupHydrated>>;
const transformAgentGroupsToOptions = (pages: AxiosResponseAgents[] = []) =>
  pages
    .flatMap((page: AxiosResponseAgents) => page.data.items)
    .map((agentGroup: AgentGroupHydrated) => ({
      label: agentGroup.name,
      value: agentGroup.id,
      ...agentGroup,
    })) || [];

const agentGroupSkeleton = (
  <Stack sx={{ flexDirection: 'row', gap: 2, alignItems: 'center', mx: 2 }}>
    <HuSkeleton
      variant="rectangular"
      height={20}
      width={25}
      sx={{
        borderRadius: 0.5,
      }}
    />
    <HuSkeleton
      variant="text"
      height={40}
      sx={{
        borderRadius: 1,
        width: '100%',
      }}
    />
  </Stack>
);

type Props = {
  name: string;
  autocompleteProps?: any;
  agentFieldName?: string;
};

function AgentGroupsAutocomplete({
  name,
  autocompleteProps,
  agentFieldName,
}: Props) {
  const [search, setSearch] = useState('');
  const { watch, setValue } = useFormContext();

  const selectedValue = watch(name);

  const currentGroupId =
    typeof selectedValue === 'string'
      ? selectedValue
      : selectedValue?.id || null;

  const previousGroupIdRef = useRef<string | null | undefined>(undefined);

  const selectedId = typeof selectedValue === 'string' ? selectedValue : null;
  const needsHydration = !!selectedId;

  const { data: hydratedData, isFetching: isFetchingHydrated } = useQuery(
    [...serviceManagementKeys.agentGroups.detail(selectedId || ''), 'hydrated'],
    () => getAgentGroup(selectedId!),
    {
      enabled: needsHydration,
      refetchOnWindowFocus: false,
    },
  );

  const agentGroupsInfiniteQuery = useInfiniteQuery(
    serviceManagementKeys.agentGroups.list(10, search),
    ({ pageParam = 1 }) =>
      getAgentGroupsHydrated({
        page: pageParam,
        limit: 10,
        name: search,
        status: AgentGroupStatus.ACTIVE,
      }),
    {
      getNextPageParam: lastPage =>
        lastPage.data.page < lastPage.data.totalPages
          ? lastPage.data.page + 1
          : undefined,
      refetchOnWindowFocus: false,
    },
  );

  const options = useMemo(
    () => transformAgentGroupsToOptions(agentGroupsInfiniteQuery?.data?.pages),
    [agentGroupsInfiniteQuery?.data?.pages],
  );

  useEffect(() => {
    if (hydratedData?.data && selectedValue !== hydratedData.data) {
      setValue(name, hydratedData.data);
    }
  }, [hydratedData, selectedValue, name, setValue]);

  // Clean agent when group changes
  useEffect(() => {
    if (previousGroupIdRef.current === undefined) {
      previousGroupIdRef.current = currentGroupId;
      return;
    }

    if (previousGroupIdRef.current !== currentGroupId && agentFieldName) {
      setValue(agentFieldName, null);
    }

    previousGroupIdRef.current = currentGroupId;
  }, [currentGroupId, agentFieldName, setValue]);

  const hasSelectedValue = !!selectedValue;

  const isLoading = agentGroupsInfiniteQuery.isFetching || isFetchingHydrated;

  return (
    <HuFormAutocomplete
      name={name}
      options={options}
      autocompleteProps={{
        disabled: isFetchingHydrated,
        getOptionLabel: (option: AgentGroupHydrated) => option?.name || '',
        isOptionEqualToValue: (
          option: AgentGroupHydrated,
          value: AgentGroupHydrated,
        ) => option?.id === value?.id,
        ...(isFetchingHydrated &&
          typeof selectedValue === 'string' && {
            renderTags: () => (
              <HuSkeleton
                variant="rounded"
                width={140}
                height={26}
                sx={{ ml: 0.5, my: 1 }}
              />
            ),
          }),
        renderOption: (
          props,
          option: AgentGroupHydrated,
          { selected, index },
        ) => {
          const { key, ...rest } = props;
          return (
            <>
              <HuMenuItem
                key={key}
                selected={selected}
                {...rest}
                sx={{ padding: '16px !important' }}
              >
                <Typography variant="globalS">{option.name}</Typography>
              </HuMenuItem>
              {index === options.length - 1 && (
                <InfiniteListAutocomplete
                  infiniteQuery={agentGroupsInfiniteQuery}
                  options={options}
                  renderSkeleton={agentGroupSkeleton}
                />
              )}
            </>
          );
        },
        onInputChange: (_, value) => setSearch(value),
        loading: agentGroupsInfiniteQuery.isFetchingNextPage || isLoading,
        isServerFiltered: true,
        ...autocompleteProps,
        placeholder: hasSelectedValue
          ? undefined
          : autocompleteProps?.placeholder,
      }}
    />
  );
}

export default AgentGroupsAutocomplete;
