import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
import {t} from 'sentry/locale';
import type {MetricMeta, MRI} from 'sentry/types/metrics';
import type {Project} from 'sentry/types/project';
import {useMutation, useQueryClient} from 'sentry/utils/queryClient';
import useApi from 'sentry/utils/useApi';
import useOrganization from 'sentry/utils/useOrganization';

import {getMetricsMetaQueryKey} from './useMetricsMeta';

type BlockMetricResponse = [MetricMeta[], unknown, unknown] | undefined;

interface MetricMetricMutationData {
  mri: MRI;
  operationType: 'blockMetric' | 'unblockMetric';
}

interface MetricTagsMutationData {
  mri: MRI;
  operationType: 'blockTags' | 'unblockTags';
  tags: string[];
}

type BlockMutationData = MetricMetricMutationData | MetricTagsMutationData;

function isTagOp(opts: BlockMutationData): opts is MetricTagsMutationData {
  return 'tags' in opts;
}

export const useBlockMetric = (project: Project) => {
  const api = useApi();
  const {slug} = useOrganization();
  const queryClient = useQueryClient();

  const options = {
    mutationFn: (data: BlockMutationData) => {
      return api.requestPromise(`/projects/${slug}/${project.slug}/metrics/visibility/`, {
        method: 'PUT',
        query: {project: project.id},
        data: {
          metricMri: data.mri,
          project: project.id,
          operationType: data.operationType,
          tags: isTagOp(data) ? data.tags : undefined,
        },
      });
    },
    onSuccess: data => {
      const metaQueryKey = getMetricsMetaQueryKey(slug, {});

      // Only match the endpoint, to search in all insances of the query
      const queryKeyFilter = {queryKey: [metaQueryKey[0]]};

      queryClient.setQueriesData(
        queryKeyFilter,
        (oldData: BlockMetricResponse): BlockMetricResponse => {
          if (!oldData) {
            return undefined;
          }
          const oldMeta = oldData[0];
          const index = oldMeta.findIndex(
            metric =>
              metric.mri === data.metricMri &&
              metric.projectIds.includes(Number(project.id))
          );

          if (index !== undefined && index !== -1) {
            const newMeta = [...oldMeta];
            newMeta[index] = {
              ...newMeta[index],
              blockingStatus: [{...data, project: project.id}],
            };

            return [newMeta, oldData[1], oldData[2]];
          }
          return oldData;
        }
      );

      addSuccessMessage(t('Metric updated'));

      queryClient.invalidateQueries(queryKeyFilter);
    },
    onError: () => {
      addErrorMessage(t('An error occurred while updating the metric'));
    },
  };

  return useMutation(options);
};
