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 FeedPendingApprovalPostList } from 'src/types/feed';
import { type ApprovalStatus } from 'src/types/groups';
import {
  type NotificationMode,
  type UnreadKeyUpdatesResponse,
} from 'src/types/key-updates';
import {
  type DraftGroupsResponse,
  type DraftPermissionResponse,
  type DraftRequest,
  type DraftRequestsResponse,
  type InsightsAudienceResponse,
  type InsightsReportResponse,
  type InsightsSummaryResponse,
  type InsightsTypes,
  type Post,
  type PostData,
  type PostRequestActionType,
  type PostViewer,
  type Voter,
} from 'src/types/posts';
import { type ReactionUsersResponse } from 'src/types/reaction';
import { type CursorPagination } from 'src/types/services';
import {
  type AudienceTypes,
  type JoinLivestreamResponse,
  type LiveStreamStats,
  type LiveStreamTimeline,
  type LiveStreamViewerReport,
  type PollResponse,
} from 'src/types/stream';
import { type ContentOnlyEditRequestPayload } from 'src/utils/postEditRequest';
import { type PaginationParams } from 'src/utils/pagination';

export const getList = (
  cursor: string,
  includeGroupPosts: boolean = false,
  searchTerm: string = '',
  limit: number = POSTS_LIMIT_PER_PAGE,
  pinned: boolean = false,
) =>
  api.get<CursorPagination<Post[]>>('posts/published', {
    params: {
      cursor: cursor || undefined,
      limit,
      q: searchTerm || undefined,
      includeGroupPosts,
      pinned,
    },
    paramsSerializer: params => qs.stringify(params),
  });

export const getScheduledPosts = (
  cursor: string,
  limit: number = POSTS_LIMIT_PER_PAGE,
) =>
  api.get<CursorPagination<Post[]>>('posts/scheduled', {
    params: {
      states: 'SCHEDULED',
      cursor: cursor || undefined,
      limit,
    },
  });

export const getPostReactionUsers = (
  postId: number,
  emoji: string,
  timestamp?: string,
) =>
  api.get<ReactionUsersResponse>(`posts/${postId}/reactions/users`, {
    params: { emoji, timestamp },
  });

export const getCommentReactionUsers = (
  postId: number,
  emoji: string,
  timestamp?: string,
) =>
  api.get<ReactionUsersResponse>(`comments/${postId}/reactions/users`, {
    params: { emoji, timestamp },
  });

export const getById = (
  id: string | number,
  options?: { skipNotFoundRedirect?: boolean },
) => api.get<Post>(`posts/${id}`, options);

export const getPostCommentsPaginated = (
  id: number,
  page: string | number,
  limit: number,
  orderBy: string = 'CREATED_AT',
  order: string = 'DESC',
) =>
  api.get<Comment[]>(`posts/${id}/comments`, {
    params: {
      page,
      limit,
      orderBy,
      order,
      childCommentsNumber: 2,
    },
  });

export const getChildCommentsPaginated = (
  id: number,
  parentId: number,
  page: number,
  limit: number,
  orderBy: string = 'CREATED_AT',
  order: string = 'DESC',
) =>
  api.get<Comment[]>(`posts/${id}/comments`, {
    params: {
      page,
      limit,
      parentId,
      orderBy,
      order,
    },
  });

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

export const removePostReaction = (id: number, emoji: string) =>
  api.post(`posts/${id}/reactions/remove`, { emoji });

export const addCommentReaction = (
  id: number,
  emoji: string,
  unified: string,
) => api.post(`comments/${id}/reactions/add`, { emoji, unified });

export const removeCommentReaction = (id: number, emoji: string) =>
  api.post(`comments/${id}/reactions/remove`, { emoji });

export const postComment = (id: number, data: any) =>
  api.post<Comment>(`posts/${id}/comments`, data);

export const updateComment = (id: number, data: any) =>
  api.put<Comment>(`/comments/${id}`, data);

export const deleteComment = (id: number) => api.delete(`/comments/${id}`);

export const enableOrDisableCommentsPost = (
  id: number,
  commentsEnabled: boolean,
) => api.put<Post>(`/posts/${id}`, { commentsEnabled });

export const createPost = (data: PostData) => api.post<Post>('posts', data);

export const updatePost = (id: number, data: PostData) =>
  api.put<Post>(`posts/${id}`, data);

export const updatePostPublicationDateTime = (
  id: number,
  publicationDateTime: any,
) => api.patch(`/posts/${id}/publication-datetime`, publicationDateTime);

export const publishPublicationNow = (id: number) =>
  api.post(`posts/${id}/publish`);

export const votePoll = (optionId: number) =>
  api.post(`polls/${optionId}/answer`);

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

export const deletePost = (id: number) => api.delete(`posts/${id}`);

export const pinPost = (postId: number) => api.post('posts/pinned', { postId });

export const unpinPost = (postId: number) =>
  api.delete(`posts/pinned/${postId}`);

export const notifyPostCommentUsers = (postId: number, bodyAttributes: any) => {
  const mentionedUserIds = bodyAttributes.map(
    (attribute: any) => attribute.type.user.id,
  );
  return api.post(`/posts/${postId}/comments/mentions`, {
    userIds: mentionedUserIds,
  });
};

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

export const getInsightsSummary = (id: number) =>
  api.get<InsightsSummaryResponse>(`posts/${id}/stats/summary`);

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

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

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

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

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

export const getFeedPendingApprovalPosts = (
  pagination: PaginationParams,
  approvalStatus: ApprovalStatus,
  actionType?: PostRequestActionType,
) =>
  api.get<FeedPendingApprovalPostList>('posts/requests', {
    params: {
      ...pagination,
      approvalStatus,
      actionType,
    },
    paramsSerializer: params => qs.stringify(params),
  });

export const reviewFeedPosts = (
  approvalStatus: ApprovalStatus,
  ids: number[],
) => api.patch('posts/review', { approvalStatus, ids });

export const deleteFeedPostRequest = (requestId: number) =>
  api.delete(`posts/requests/${requestId}`);

export const requestFeedPostEdition = (
  id: number,
  data: ContentOnlyEditRequestPayload,
) => api.post(`posts/${id}/edit-requests`, data);

export const getDraftPermissions = (params: {
  limit: number;
  cursor: string;
  type?: 'FOR_CREATION' | 'AS_END_USER';
}) =>
  api.get<DraftPermissionResponse>('posts/drafts/permissions', {
    params,
  });

export const getDraftGroups = (id: number, params: any) =>
  api.get<DraftGroupsResponse>(`posts/drafts/permissions/${id}/groups`, {
    params,
  });

export const getDraftFeed = (id: number) =>
  api.get<{
    canPostInFeed: boolean;
    canSendPostNotification: boolean;
    canCreatePoll: boolean;
  }>(`posts/drafts/permissions/${id}/feed`);

export const createFeedPostDraft = (permissionId: number, data: PostData) =>
  api.post<Post>('posts/drafts/requests/feed', { ...data, permissionId });

export const createGroupsPostDraft = (
  permissionId: number,
  groupId: number,
  data: PostData,
) =>
  api.post<Post>('posts/drafts/requests/groups', {
    ...data,
    permissionId,
    groupId,
  });

export const getDraftRequests = (params: any) =>
  api.get<DraftRequestsResponse>('posts/drafts/requests', {
    params,
  });

export const getDraftRequestsMine = (params: any) =>
  api.get<DraftRequestsResponse>('posts/drafts/requests/mine', {
    params,
  });

export const reviewDraftPost = (id: number, approvalStatus: ApprovalStatus) =>
  api.patch(`posts/drafts/requests/${id}`, { approvalStatus });

export const updatePostDraft = (id: number, data: PostData) =>
  api.put<Post>(`posts/drafts/requests/${id}`, data);

export const cancelDraft = (id: number) =>
  api.delete(`posts/drafts/requests/${id}`);

export const updatePostDraftSchedule = (
  id: number,
  data: {
    publicationDatetime: string | Date;
    sendNotification?: boolean;
  },
) =>
  api.put<DraftRequest>(`posts/drafts/requests/${id}/publication-datetime`, {
    publicationDatetime: data.publicationDatetime,
    sendNotification: data.sendNotification,
  });

export const getDraftDetail = (id: string | number) =>
  api.get<DraftRequest>(`posts/drafts/requests/${id}`);

export const markPostAsKeyUpdate = (
  id: number,
  notificationModes?: NotificationMode[],
  previewExpiresAt?: Date,
) => {
  return api.post<Post>(`posts/${id}/key-update`, {
    notificationModes,
    previewExpiresAt,
  });
};

export const unmarkPostAsKeyUpdate = (id: number) =>
  api.delete<Post>(`posts/${id}/key-update`);

export const getUnreadKeyUpdatesCount = () =>
  api.get<UnreadKeyUpdatesResponse>('red-bubbles/key-updates');

export const markKeyUpdateAsRead = (id?: number): Promise<void> =>
  api.post(`posts/${id}/key-update/read`);

export const getKeyUpdates = (
  cursor: string,
  unreadKeyUpdates: boolean = false, // False brings all key updates, true brings only unread key updates
  limit: number = 20,
) => {
  return api.get<CursorPagination<Post[]>>(`posts/key-updates`, {
    params: {
      cursor,
      limit,
      unreadKeyUpdates,
    },
  });
};

export const getKeyUpdatesPreview = (limit: number = 2) => {
  return api.get<CursorPagination<Post[]>>(`posts/key-updates-preview`, {
    params: {
      limit,
    },
  });
};

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

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

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

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

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

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

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