// if we remove a user directly from the form, the query key changes and all pages are removed from cache
// we need to keep track of the removed users and modify the form only when it is saved
import { useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { useInfiniteQuery, useQuery } from 'react-query';

import { set } from 'lodash-es';

import { usersKeys } from 'src/pages/dashboard/Users/queries';
import * as usersService from 'src/services/usersService';
import { type SegmentationType } from 'src/types/user';
import { formatSegmentationIds } from 'src/utils/segmentationUtils';

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

export const useSegmentationPreview = (
  name: string,
  useAudienceApi = false,
) => {
  const { watch, setValue } = useFormContext();
  const values = watch(name);

  const [removedUsers, setRemovedUsers] = useState([]);

  const { userSegmentation, groupSegmentation } = values || {};
  const { segmentationUserIds, segmentationItemIds } = formatSegmentationIds({
    userSegmentation,
    groupSegmentation,
  });

  const previewParams = {
    ids: segmentationUserIds,
    segmentationItemIds,
    limit: 200,
    orderBy: 'NAME',
    order: 'ASC',
  };

  const enabled =
    !!segmentationUserIds?.length || !!segmentationItemIds?.length;

  const audienceQuery = useInfiniteQuery(
    usersKeys.audience(previewParams),
    ({ pageParam = 0 }) =>
      usersService.getAudience(
        { ...previewParams, page: pageParam },
        useAudienceApi,
      ),
    {
      enabled,
      keepPreviousData: enabled,
      getNextPageParam: lastPage =>
        lastPage.data.page === lastPage.data.totalPages
          ? undefined
          : lastPage.data.page,
    },
  );

  const { data: unsegmentedUsers = [], isLoading } = useQuery(
    usersKeys.unsegmented(segmentationUserIds, segmentationItemIds),
    () =>
      usersService.getUnsegmentedUsers(
        segmentationItemIds,
        segmentationUserIds,
      ),
    {
      select: response => response.data.userIds,
      enabled: !!segmentationItemIds.length && !!segmentationUserIds.length,
    },
  );

  const totalUsers =
    (audienceQuery.data?.pages[0].data.count || 0) - removedUsers.length;

  const users = audienceQuery.data?.pages
    .flatMap(page => page.data.items)
    .filter(u => !removedUsers.includes(u.id));

  const removeUser = (id: number) => setRemovedUsers(prev => prev.concat(id));

  const updateForm = () =>
    setValue(
      `${name}.userSegmentation`,
      userSegmentation.filter(u => !removedUsers.includes(u.id)),
    );

  return {
    unsegmentedUsers,
    totalUsers,
    audienceQuery,
    users,
    removeUser,
    updateForm,
    loading: isLoading || audienceQuery.isLoading,
  };
};

// Use this if you only need to preview the total amount of users
export const useSimpleSegmentationPreview = (
  name: string,
  useAudienceApi = false,
) => {
  const { watch } = useFormContext();
  const values = watch(name);

  const { userSegmentation, groupSegmentation } = values || {};

  const { segmentationUserIds, segmentationItemIds } = formatSegmentationIds({
    userSegmentation,
    groupSegmentation,
  });

  const previewParams = {
    ids: segmentationUserIds,
    segmentationItemIds,
    limit: 1,
  };

  const enabled =
    !!segmentationUserIds?.length || !!segmentationItemIds?.length;

  const { data = 0, isLoading } = useQuery(
    usersKeys.audience(previewParams),
    () =>
      usersService.getAudienceCount(
        { ...previewParams, page: 0 },
        useAudienceApi,
      ),
    {
      enabled,
      select: response => response.data.count,
      refetchOnMount: false,
    },
  );

  return {
    totalUsers: data,
    loading: isLoading,
  };
};

export const formatSegmentationInSections = (
  segmentationGroups: SegmentationType[],
  groupSegmentation: number[],
) => {
  const result: Record<string, string[]> = {};

  segmentationGroups.forEach(group => {
    group.items.forEach(item => {
      if (groupSegmentation.includes(item.id)) {
        result[group.name] = [...(result[group.name] || []), item.name];
      }
    });
  });

  return result;
};

export const formatSegmentationForSelection = (
  segmentation: SegmentationType[],
  selectedItems: number[],
) => {
  const formattedSegmentation: SegmentationForSelection = [];

  segmentation?.forEach(group => {
    if (!group) return;

    let checkedCount = 0;
    const formattedItems: {
      id: number;
      name: string;
      checked: boolean;
    }[] = [];

    group.items?.forEach(item => {
      const checked = selectedItems?.includes(item.id) || false;

      checkedCount += checked ? 1 : 0;

      formattedItems.push({
        id: item.id,
        name: item.name,
        checked,
      });
    });

    formattedSegmentation.push({
      id: group.id,
      name: group.name,
      items: formattedItems,
      count: formattedItems.length,
      checkedCount,
    });
  });

  return formattedSegmentation;
};

export const changeSegmentation = (
  segmentation: SegmentationForSelection,
  groupIndex: number,
  itemIndex: number,
  newChecked: boolean,
) => {
  const newSegmentation = segmentation;

  set(
    newSegmentation,
    `[${groupIndex}].items[${itemIndex}].checked`,
    newChecked,
  );

  set(
    newSegmentation,
    `[${groupIndex}].checkedCount`,
    newSegmentation[groupIndex].checkedCount + (newChecked ? 1 : -1),
  );

  return newSegmentation;
};
