import { type AxiosRequestConfig } from 'axios';
import qs from 'qs';

import api from 'src/config/api';
import { POSTS_LIMIT_PER_PAGE } from 'src/constants/posts';
import { type Comment } from 'src/types/comments';
import {
  type ActiveMembersResponse,
  type ApprovalStatus,
  type Group,
  type GroupBodyRequest,
  type GroupCommentList,
  type GroupCompany,
  type GroupMember,
  type GroupNotificationConfiguration,
  type GroupNotificationConfigurationConfigModes,
  type GroupPendingApprovalPostList,
  type GroupPost,
  type GroupPostList,
  type GroupReactionUsersResponse,
  type GroupRequest,
  type GroupSchedulePostList,
  type GroupStatsSummary,
  type GroupsNotificationsResponse,
} from 'src/types/groups';
import {
  type InsightsAudienceResponse,
  type InsightsReportResponse,
  type InsightsSummaryResponse,
  type InsightsTypes,
  type Post,
  type PostData,
  type PostRequestActionType,
  type PostViewer,
  type Voter,
} from 'src/types/posts';
import { type CursorPagination, type Pagination } from 'src/types/services';
import {
  type AudienceTypes,
  type JoinLivestreamResponse,
  type LiveStreamStats,
  type LiveStreamTimeline,
  type LiveStreamViewerReport,
  type PollResponse,
} from 'src/types/stream';
import { type User } from 'src/types/user';
import { type PaginationParams } from 'src/utils/pagination';
import { type ContentOnlyEditRequestPayload } from 'src/utils/postEditRequest';

export const getGroups = (params: AxiosRequestConfig<any>['params']) =>
  api.get<Pagination<Group[]>>('groups', { params });

export const getPostableGroups = (params: {
  page?: number;
  limit?: number;
  q?: string;
}) =>
  api.get<Pagination<Group[]>>('groups', {
    params: { ...params, canPost: true },
  });

export const exploreGroups = (params: AxiosRequestConfig<any>['params']) =>
  api.get<CursorPagination<Group[]>>('groups/explore', { params });

export const getGroupDetails = (groupId: string) =>
  api.get<Group>(`groups/${groupId}`);

export const editGroup = (groupId: string, body: GroupBodyRequest) =>
  api.patch<Group>(`groups/${groupId}`, body);

export const getGroupMembers = (
  id: string,
  cursor: string = '',
  searchTerm: string = '',
  limit: number = 20,
) =>
  api.get(`/groups/${id}/members`, {
    params: {
      cursor: cursor || undefined,
      limit,
      q: searchTerm || undefined,
    },
    paramsSerializer: params => qs.stringify(params),
  });

export const getManageGroupMembers = (
  id: string,
  { page, ...other }: AxiosRequestConfig<any>['params'],
) =>
  api.get<Pagination<GroupMember[]>>(`/groups/${id}/members`, {
    params: {
      page: page,
      ...other,
    },
  });

export const getGroupRequests = (
  id: string,
  { page, ...other }: AxiosRequestConfig<any>['params'],
) =>
  api.get<Pagination<GroupRequest[]>>(`/groups/${id}/requests`, {
    params: {
      page: page + 1,
      ...other,
    },
  });

export const updateGroupRequest = (
  id: string,
  requestId: number,
  status: string,
) => api.put(`/groups/${id}/requests/${requestId}/status`, { status });

export const updateAllGroupRequests = (id: string, status: string) =>
  api.put(`/groups/${id}/requests/status`, { status });

export const addMembers = (
  id: string,
  userIds: number[],
  adminIds?: number[],
) => api.put(`/groups/${id}/members`, { userIds, adminIds });

export const inviteMembers = (id: string, userIds: number[]) =>
  api.post(`/groups/${id}/invite`, { userIds });

export const removeMember = (id: string, userId: number) =>
  api.delete(`/groups/${id}/members/${userId}`);

export const leaveGroup = (groupId: string) =>
  api.delete(`/groups/${groupId}/membership`);

export const updateMemberRole = (id: string, userId: number, body: any) =>
  api.put(`/groups/${id}/members/${userId}/role`, body);

export const acceptMemberRequest = (id: string, userId: number) =>
  api.put(`/groups/${id}/members/${userId}/role`);

export const createGroupPost = (id: string | number, data: PostData) =>
  api.post<GroupPost>(`/groups/${id}/posts`, data);

export const pinGroupPost = (groupId: string, postId: number) =>
  api.post(`/groups/${groupId}/posts/${postId}/pin`, { postId });

export const unpinGroupPost = (groupId: string, postId: number) =>
  api.post(`/groups/${groupId}/posts/${postId}/unpin`);

export const updateGroupPost = (
  groupId: string,
  postId: number,
  data: PostData,
) => api.put<GroupPost>(`/groups/${groupId}/posts/${postId}`, data);

export const updateGroupPostComment = (
  groupId: string | number,
  postId: number,
  commentId: number,
  data: Comment,
) =>
  api.put<Comment>(
    `/groups/${groupId}/posts/${postId}/comments/${commentId}`,
    data,
  );

export const joinGroup = (id: string | number) =>
  api.post(`/groups/${id}/join`);

export const cancelJoinRequest = (
  groupId: string | number,
  requestId: number,
) => api.post(`/groups/${groupId}/requests/${requestId}/cancel`);

export const getGroupPosts = (
  id: string,
  cursor: string = '',
  searchTerm: string = '',
  pinned: boolean = false,
  limit: number = POSTS_LIMIT_PER_PAGE,
) =>
  api.get<GroupPostList>(`/groups/${id}/posts`, {
    params: {
      cursor: cursor || undefined,
      limit,
      q: searchTerm || undefined,
      pinned,
    },
    paramsSerializer: params => qs.stringify(params),
  });

export const getGroupScheduledPosts = (
  id: string,
  page: number = 1,
  limit: number = POSTS_LIMIT_PER_PAGE,
) =>
  api.get<GroupSchedulePostList>(`/groups/${id}/scheduled-posts`, {
    params: {
      page,
      limit,
    },
    paramsSerializer: params => qs.stringify(params),
  });

export const getGroupPostDetails = (
  groupId: string | number,
  postId: string | number,
  options?: { skipNotFoundRedirect?: boolean },
) => api.get<GroupPost>(`groups/${groupId}/posts/${postId}`, options);

export const postGroupComment = (
  postId: number,
  body: any,
  groupId: string | number,
) => api.post<Comment>(`groups/${groupId}/posts/${postId}/comments`, body);

export const getGroupPostCommentsPaginated = (
  postId: number,
  cursor: string | number,
  groupId: string | number,
  limit: string | number,
  orderBy: string = 'CREATED_AT',
  order: string = 'DESC',
) =>
  api.get<GroupCommentList>(`groups/${groupId}/posts/${postId}/comments`, {
    params: {
      cursor,
      limit,
      orderBy,
      order,
      childCommentsNumber: 2,
    },
  });

export const getGroupPostChildCommentsPaginated = (
  id: number,
  groupId: string | number,
  parentId: number,
  cursor: string,
  limit: number,
) =>
  api.get<GroupCommentList>(`groups/${groupId}/posts/${id}/comments`, {
    params: {
      cursor,
      limit,
      parentId,
      orderBy: 'CREATED_AT',
      order: 'DESC',
    },
  });

export const voteGroupPoll = (
  groupId: string,
  postId: number,
  pollId: number,
  optionId: number,
) =>
  api.post(
    `/groups/${groupId}/posts/${postId}/polls/${pollId}/options/${optionId}/answer`,
  );

export const updateGroupPollDeadline = (
  groupId: number,
  postId: number,
  pollId: number,
  endsAt: string | null,
) =>
  api.patch(`/groups/${groupId}/posts/${postId}/polls/${pollId}/ends-at`, {
    endsAt,
  });

export const getGroupPollVoters = (
  groupId: number,
  postId: number,
  pollId: number,
  pollOptionId: number,
  limit: number,
  cursor?: string,
) =>
  api.get<CursorPagination<Voter[]>>(
    `groups/${groupId}/posts/${postId}/polls/${pollId}/options/${pollOptionId}/voters`,
    {
      params: {
        limit,
        cursor,
      },
    },
  );

export const addGroupPostReaction = (
  id: number,
  groupId: string | number,
  emoji: string,
  unified: string,
) => api.post(`groups/${groupId}/posts/${id}/reactions`, { emoji, unified });

export const removeGroupPostReaction = (
  id: number,
  groupId: string | number,
  emoji: string,
) => api.delete(`groups/${groupId}/posts/${id}/reactions`, { data: { emoji } });

export const addGroupCommentReaction = (
  id: number,
  postId: number,
  groupId: string | number,
  emoji: string,
  unified: string,
) =>
  api.post(`groups/${groupId}/posts/${postId}/comments/${id}/reactions`, {
    emoji,
    unified,
  });

export const removeGroupCommentReaction = (
  id: number,
  postId: number,
  groupId: string | number,
  emoji: string,
) =>
  api.delete(`groups/${groupId}/posts/${postId}/comments/${id}/reactions`, {
    data: { emoji },
  });

export const getGroupPostReactionUsers = (
  postId: number,
  groupId: string | number,
  emoji: string,
  cursor: string,
  limit = 30,
) =>
  api.get<GroupReactionUsersResponse>(
    `groups/${groupId}/posts/${postId}/reactions/users`,
    { params: { emoji, limit, cursor } },
  );

export const getGroupCommentReactionUsers = (
  postId: number,
  groupId: string | number,
  commentId: number,
  emoji: string,
  cursor: string,
  limit = 10,
) =>
  api.get<GroupReactionUsersResponse>(
    `groups/${groupId}/posts/${postId}/comments/${commentId}/reactions/users`,
    { params: { emoji, limit, cursor } },
  );

export const deleteGroupPost = (postId: number, groupId: string | number) =>
  api.delete(`/groups/${groupId}/posts/${postId}`);

export const rescheduleGroupPost = (
  postId: number,
  groupId: string | number,
  publicationDatetime: string | Date,
  sendNotification: boolean,
) =>
  api.patch(`/groups/${groupId}/posts/${postId}/publication-datetime`, {
    publicationDatetime,
    sendNotification,
  });

export const deleteGroupComment = (
  postId: number,
  groupId: string | number,
  commentId: number,
) => api.delete(`groups/${groupId}/posts/${postId}/comments/${commentId}`);

export const getGroupsNotifications = () =>
  api.get<GroupsNotificationsResponse>('red-bubbles/groups');

export const clearGroupsNotifications = (id: string) =>
  api.post(`red-bubbles/groups/${id}/clear`);

export const getAssignableMembers = (
  groupId: string,
  pagination: Pick<PaginationParams, 'page' | 'limit' | 'search'>,
) =>
  api.get<Pagination<User[]>>(`groups/${groupId}/assignable-members`, {
    params: {
      ...pagination,
      q: pagination.search || undefined,
    },
  });

export const createGroup = (body: GroupBodyRequest) =>
  api.post<Group>('groups', body);

export const getTranslatedPost = (id: string, postId: number) =>
  api.get(`groups/${id}/posts/${postId}/translation`);

export const getGroupPendingApprovalPosts = (
  groupId: string,
  pagination: PaginationParams,
  approvalStatus: ApprovalStatus,
  actionType?: PostRequestActionType,
) =>
  api.get<GroupPendingApprovalPostList>(`groups/${groupId}/post-requests`, {
    params: {
      ...pagination,
      approvalStatus,
      actionType,
    },
    paramsSerializer: params => qs.stringify(params),
  });

export const reviewGroupPosts = (
  groupId: string,
  approvalStatus: ApprovalStatus,
  ids: number[],
) => api.patch(`groups/${groupId}/posts/review`, { approvalStatus, ids });

export const deleteGroupPostRequest = (groupId: string, requestId: number) =>
  api.delete(`groups/${groupId}/post-requests/${requestId}`);

export const requestGroupPostEdition = (
  groupId: string,
  postId: number,
  data: ContentOnlyEditRequestPayload,
) => api.post(`groups/${groupId}/posts/${postId}/edit-requests`, data);

export const setGroupPostViewed = (id: number, groupId: number) =>
  api.post(`groups/${groupId}/posts/${id}/viewed`);

export const getGroupPostInsightsSummary = (groupId: number, postId: number) =>
  api.get<InsightsSummaryResponse>(
    `groups/${groupId}/posts/${postId}/stats/summary`,
  );

export const getGroupPostInsightsAudience = (
  groupId: string,
  id: number,
  type: InsightsTypes,
  page: number = 1,
  limit: number = 25,
  search: string = '',
) =>
  api.get<InsightsAudienceResponse>(
    `groups/${groupId}/posts/${id}/stats/${type}`,
    {
      params: {
        page,
        limit,
        search: search || undefined,
      },
      paramsSerializer: params => qs.stringify(params),
    },
  );

export const getGroupPostViewers = (
  groupId: string | number,
  postId: number,
  limit: number = 25,
  cursor?: string,
  search?: string,
) =>
  api.get<CursorPagination<PostViewer[]>>(
    `groups/${groupId}/posts/${postId}/views`,
    {
      params: {
        limit,
        cursor: cursor || undefined,
        q: search || undefined,
      },
      paramsSerializer: params => qs.stringify(params),
    },
  );

export const getGroupPostInsightsSummaryReport = (
  groupId: number,
  postId: number,
) =>
  api.get<InsightsReportResponse>(
    `groups/${groupId}/posts/${postId}/stats/summary/report`,
    {
      responseType: 'blob',
    },
  );

export const getGroupPostInsightsAudienceReport = (
  groupId: number,
  postId: number,
) =>
  api.get<InsightsReportResponse>(
    `groups/${groupId}/posts/${postId}/stats/audience/report`,
    {
      responseType: 'blob',
    },
  );

export const getGroupMembersReport = (groupId: string, email: string) =>
  api.get(`groups/${groupId}/members/report`, { params: { email } });

export const getGroupNotificationConfiguration = (
  groupId: string,
  modes: GroupNotificationConfigurationConfigModes[],
) =>
  api.get<GroupNotificationConfiguration>(
    `groups/${groupId}/notification-configuration`,
    {
      params: { modes: modes.join(',') },
    },
  );

export const updateGroupNotificationConfiguration = (
  groupId: string,
  mode: GroupNotificationConfigurationConfigModes,
  enabled: boolean,
) =>
  api.put(`groups/${groupId}/notification-configuration`, {
    mode,
    enabled,
  });

export const getGroupStatsSummary = (groupId: string) =>
  api.get<GroupStatsSummary>(`groups/${groupId}/stats/summary`);

export const getGroupMostActiveMembers = (groupId: string) =>
  api.get<ActiveMembersResponse>(`groups/${groupId}/stats/most-active-members`);

export const getGroupMostActiveMembersReport = (
  groupId: string,
  email: string,
) =>
  api.get(`groups/${groupId}/stats/most-active-members/report`, {
    params: { email },
  });

export const getGroupLiveStreamTimeline = (groupId: string, postId: string) =>
  api.get<LiveStreamTimeline>(
    `/groups/${groupId}/posts/${postId}/livestream_viewers_timeline`,
  );

export const getGroupLiveStreamStats = (groupId: string, postId: string) =>
  api.get<LiveStreamStats>(
    `/groups/${groupId}/posts/${postId}/livestream_stats`,
  );

export const getGroupLiveStreamViewerReports = ({
  groupId,
  postId,
  q,
  limit,
  cursor,
  audienceType,
}: {
  groupId: string;
  postId: string;
  q: string;
  limit: number;
  cursor: string;
  audienceType: AudienceTypes;
}) =>
  api.get<CursorPagination<LiveStreamViewerReport[]>>(
    `/groups/${groupId}/posts/${postId}/${audienceType}`,
    {
      params: { q, limit, cursor },
    },
  );

export const pinGroup = (groupId: number) => api.post(`groups/${groupId}/pin`);

export const unpinGroup = (groupId: number) =>
  api.delete(`groups/${groupId}/pin`);

export const sortPinnedGroups = ({
  groupId,
  parentGroupId,
}: {
  groupId: number;
  parentGroupId?: number;
}) => api.patch(`groups/${groupId}/pin`, { parentGroupId });

export const getGroupLiveStreamReport = (groupId: string, postId: string) =>
  api.get<BlobPart>(
    `groups/${groupId}/posts/${postId}/stats/livestream/report`,
    {
      responseType: 'blob',
    },
  );

export const joinLiveStream = (groupId: number, postId: number) =>
  api.post<JoinLivestreamResponse>(
    `groups/${groupId}/posts/${postId}/livestream_join`,
  );

export const getGroupLiveStreamPoll = (postId: number, groupId: number) =>
  api.get<PollResponse>(`groups/${groupId}/posts/${postId}/livestream_poll`);

export const voteGroupLiveStreamPoll = (
  postId: number,
  groupId: number,
  pollId: number,
  pollOptionId: number,
) =>
  api.post(`/groups/${groupId}/posts/${postId}/livestream_poll_answer`, {
    pollId,
    pollOptionId,
  });

export const getGroupsPostsForUser = (
  id: number,
  cursor: string,
  limit: number,
) =>
  api.get<CursorPagination<Post[]>>(`groups/user/${id}/posts`, {
    params: { cursor, limit },
  });

export const enableOrDisableCommentsGroupPost = (
  groupId: string | number,
  postId: number,
  commentsEnabled: boolean,
) =>
  api.patch<GroupPost>(`/groups/${groupId}/posts/${postId}`, {
    commentsEnabled,
  });

export const archiveGroup = (groupId: string | number, isArchived: boolean) =>
  api.patch<Group>(`/groups/${groupId}/archive`, { isArchived });

export const getMultiCompanyGroupCompanies = (
  groupId: string,
  cursor: string,
  limit: number = 20,
) =>
  api.get<CursorPagination<GroupCompany[]>>(
    `/groups/${groupId}/linked-instances`,
    {
      params: {
        cursor,
        limit,
      },
    },
  );

export const getMultiCompanyGroupCompaniesCount = (groupId: string) =>
  api.get<{ count: number }>(`/groups/${groupId}/linked-instances/count`);
