import { AxiosResponse } from 'axios';

import { queryClient } from 'src/config/react-query';
import { Poll, PollsResponse } from 'src/types/stream';

export const livestreamKeys = {
  all: () => ['livestream'],
  thumbnail: (url: string) => [...livestreamKeys.all(), 'thumbnail', url],
  polls: (streamId: string) => [...livestreamKeys.all(), 'polls', streamId],
};

export const invalidatePollDataQueries = (streamId: string) => {
  queryClient.invalidateQueries(livestreamKeys.polls(streamId));
};

export const pushPollData = (streamId: string, poll: Poll) => {
  queryClient.setQueryData<AxiosResponse<PollsResponse> | undefined>(
    livestreamKeys.polls(streamId),
    oldData => {
      if (!oldData) return oldData;

      return {
        ...oldData,
        data: {
          ...oldData.data,
          polls: [...oldData.data.polls, poll],
        },
      };
    },
  );
  invalidatePollDataQueries(streamId);
};

export const updatePollData = (streamId: string, updatedPoll: Poll) => {
  queryClient.setQueryData<AxiosResponse<PollsResponse> | undefined>(
    livestreamKeys.polls(streamId),
    oldData => {
      if (!oldData) return oldData;

      return {
        ...oldData,
        data: {
          ...oldData.data,
          polls: oldData.data.polls.map(poll =>
            poll.id === updatedPoll.id ? updatedPoll : poll,
          ),
        },
      };
    },
  );
  invalidatePollDataQueries(streamId);
};

export const optimisticUpdatePollData = async (
  streamId: string,
  updatedPoll: Poll,
) => {
  await queryClient.cancelQueries(livestreamKeys.polls(streamId));
  const previousPolls = queryClient.getQueryData<AxiosResponse<PollsResponse>>(
    livestreamKeys.polls(streamId),
  );
  queryClient.setQueryData<AxiosResponse<PollsResponse> | undefined>(
    livestreamKeys.polls(streamId),
    oldData => {
      if (!oldData) return oldData;
      return {
        ...oldData,
        data: {
          ...oldData.data,
          polls: oldData.data.polls.map(poll =>
            poll.id === updatedPoll.id ? updatedPoll : poll,
          ),
        },
      };
    },
  );
  return previousPolls;
};

export const optimisticPollDataRestore = (
  streamId: string,
  previousPolls: AxiosResponse<PollsResponse> | undefined,
) => {
  queryClient.setQueryData(livestreamKeys.polls(streamId), previousPolls);
};

export const deletePollData = (streamId: string, pollId: number) => {
  queryClient.setQueryData<AxiosResponse<PollsResponse> | undefined>(
    livestreamKeys.polls(streamId),
    oldData => {
      if (!oldData) return oldData;
      return {
        ...oldData,
        data: {
          ...oldData.data,
          polls: oldData.data.polls.filter(poll => poll.id !== pollId),
        },
      };
    },
  );
  invalidatePollDataQueries(streamId);
};

export const incrementPollOptionVote = (
  streamId: string,
  pollId: number,
  pollOptionId: number,
) => {
  queryClient.setQueryData<AxiosResponse<PollsResponse> | undefined>(
    livestreamKeys.polls(streamId),
    oldData => {
      if (!oldData) return oldData;
      return {
        ...oldData,
        data: {
          ...oldData.data,
          polls: oldData.data.polls.map(poll =>
            poll.id === pollId
              ? {
                  ...poll,
                  totalAnswerCount: poll.totalAnswerCount + 1,
                  pollOptions: poll.pollOptions.map(option =>
                    option.id === pollOptionId
                      ? { ...option, answerCount: option.answerCount + 1 }
                      : option,
                  ),
                }
              : poll,
          ),
        },
      };
    },
  );
  invalidatePollDataQueries(streamId);
};
