import {
  Asset,
  ChatEvent,
  ChatUser,
  ConversationFromServer,
  FileAsset,
  MessageEvent,
  PictureAsset,
  HighlightedSpan,
  ConversationProperties,
  MessageInfoReadState,
  SearchMessageMatchItem,
  GeneratedBy,
} from '@modules/chats/interfaces';

import {MembershipFromServer} from '../interfaces/models/membership';

export interface BaseResponse {
  ok: boolean;
  error?: string;
}
export interface CursorBaseResponse extends BaseResponse {
  response_metadata?: {
    next_cursor: Nullable<string>;
  };
}

export interface CursorParams {
  cursor?: Nullable<string>;
  limit?: number;
}

export interface GetConversationsParams extends CursorParams {
  search?: string;
  /**
   * Include only `Conversation` with unread messages
   */
  unread?: boolean;
}

export interface GetConversationsResponse extends CursorBaseResponse {
  channels: ConversationFromServer[];
}

export interface GetConversationInfoParams {
  channel: string;
  fromServer?: boolean;
}

export interface GetConversationInfoResponse extends BaseResponse {
  channel: ConversationFromServer;
}

export interface ConversationMembersParams extends CursorParams {
  channel: string;
}

export interface ConversationMembersResponse extends CursorBaseResponse {
  members: string[];
}

export interface ConversationMembershipsResponse extends CursorBaseResponse {
  memberships: MembershipFromServer[];
}
export interface GetUsersListParams extends CursorParams {
  user?: number;
  q?: string;
  userIds?: string;
  notInChannel?: string;
}

export interface GetUsersListResponse extends CursorBaseResponse {
  members: ChatUser[];
}

export interface GetUserInfoParams {
  user: number;
  fromServer?: boolean;
}

export interface ConversationOpenParams {
  users: ChatUser[];
  prevent_creation?: boolean;
}

export interface UpdateConversationParams {
  channel: string;
  name?: string;
  picture?: PictureAsset;
  description?: string;
  idempotencyKey: string;
}
export interface ConversationCreateParams {
  name: string;
  users: ChatUser[];
  picture?: PictureAsset;
}

export interface ConversationInviteParams {
  channel: string;
  users: string[];
}

export interface ConversationGrantAdminParams {
  channel: string;
  user: string;
}

export interface ConversationKickParams {
  channel: string;
  user: string;
}
export interface ConversationOpenResponse extends BaseResponse {
  no_op?: boolean;
  channel: ConversationFromServer;
}

export interface GetUserInfoResponse extends BaseResponse {
  user: ChatUser;
}

export interface GetUsersInfoResponse extends BaseResponse {
  members: ChatUser[];
}

export interface GetConversationHistoryParams extends CursorParams {
  channel: string;
  inclusive?: boolean;
  /**
   * ULID timestamp
   */
  latest?: string;
  /**
   * ULID timestamp
   */
  oldest?: string;
}

export interface GetConversationHistoryResponse extends CursorBaseResponse {
  messages: MessageEvent[];
}

export interface GetConversationHistoryPeakResponse extends BaseResponse {
  messages: MessageEvent[];
  response_metadata?: {
    next_cursor?: Nullable<string>;
    prev_cursor?: Nullable<string>;
  };
}

export interface PostMessageParams {
  channel: string;
  text: string;
  idempotencyKey: string;
  messageId?: string;
  attachments?: Asset[];
  generated_by?: GeneratedBy;
  reply_ts?: string;
}

export interface ForwardMessageParams
  extends Omit<PostMessageParams, 'reply_ts'> {
  destinationUserIds: number[];
  destinationChannelIds: string[];
}

export interface PostMessageResponse extends BaseResponse {
  message: MessageEvent;
}

export interface ForwardMessageResponse extends BaseResponse {
  forwarded_messages: MessageEvent[];
}

export type GetEventsParams = Omit<GetConversationHistoryParams, 'channel'>;

export type GetRecentParams = {
  limit?: number;
  cursor?: Nullable<string>;
};

export interface GetEventsResponse extends CursorBaseResponse {
  messages: ChatEvent[];
}

export interface GetRecentResponse extends CursorBaseResponse {
  conversations: {
    group_conversation: ConversationFromServer;
    latest_messages: MessageEvent[];
  }[];
}

export interface PostConversationsMarkReceivedParams {
  channel: string;
  last_received_message_ts: string;
  idempotencyKey: string;
}

export interface PostConversationsMarkParams {
  channel: string;
  idempotencyKey: string;
  ts?: string;
}

export interface PostConversationsMarkResponse extends BaseResponse {}
export interface ConversationKickResponse extends BaseResponse {
  membership: MembershipFromServer;
}

export interface ConversationGrantAdminResponse extends BaseResponse {
  membership: MembershipFromServer;
}

export type GenerateAssetParams = Pick<
  FileAsset,
  | 'contentType'
  | 'name'
  | 'type'
  | 'public'
  | 'height'
  | 'width'
  | 'externalReference'
  | 'metadata'
> & {size?: string} & Partial<Pick<FileAsset, 'thumbnailUrl'>>;

export type GenerateAssetResponse = BaseResponse & FileAsset;

export interface GetUsersUpdatesParams extends CursorParams {
  fromDate?: number;
}

export interface GetUsersUpdatesResponse extends CursorBaseResponse {
  members: ChatUser[];
}

export interface EditMessageParams {
  /**
   * The channel ULID
   */
  channel: string;
  /**
   * The message ULID
   */
  ts: string;
  /**
   * The new message text
   */
  text: string;
  /**
   * The idempotency key
   */
  idempotencyKey: string;
  /**
   * The highlighted spans.
   * This is only used on edit messages. Backend will not process this field.
   */
  highlighted_spans?: HighlightedSpan[];
  /**
   * The formatted text.
   * This is only used on edit messages. Backend will not process this field.
   */
  formatted_text?: string;
}

export interface EditMessageResponse extends BaseResponse {
  message: MessageEvent;
}

export interface ToggleReactionParams {
  channel: string;
  /**
   * The `ts` (server ULID) of the message to react to
   */
  ts: string;
  /**
   * The reaction name
   */
  name: string;
  /**
   * Action type: add or remove reaction
   */
  type: 'add' | 'remove';
  /**
   * The idempotency key
   */
  idempotencyKey: string;
}

export interface ToggleReactionResponse extends BaseResponse {}

export interface GetReactionsParams {
  channel: string;
  /**
   * The `ts` (server ULID) of the message
   */
  ts: string;
  full: boolean;
}

export interface GetReactionsResponse extends BaseResponse {
  message: MessageEvent;
}

export interface DeleteMessageParams {
  channel: string;
  /**
   * The `ts` (server ULID) of the message to delete
   */
  ts: string;
  idempotencyKey: string;
}

export interface ReadChannelParams {
  channel: string;
  idempotencyKey: string;
  ts?: string;
}

export interface ReadChannelResponse extends BaseResponse {}

export interface DeleteMessageResponse extends BaseResponse {}

export interface SetConversationPropertiesParams {
  channel: string;
  properties: ConversationProperties;
  idempotencyKey: string;
}

export interface SetConversationPropertiesResponse extends BaseResponse {
  channel: ConversationFromServer;
}

export interface MessageInfoResponse extends CursorBaseResponse {
  message: MessageEvent;
  total_read_count: number;
  member_count_at_creation: number;
  read_states: MessageInfoReadState[];
  response_metadata: {next_cursor: string};
}

export type SearchMessagesRequestParams = {
  channelId: string;
  query: string;
  cursor?: string;
  limit?: number;
  sortDir?: 'asc' | 'desc';
  signal?: AbortSignal;
} & CursorParams;

export interface SearchMessagesResponse extends CursorBaseResponse {
  matches: SearchMessageMatchItem[];
}

export interface AddPinnedMessageParams {
  channel: string;
  ts: string;
  expiresAt: string;
  idempotencyKey: string;
}

export interface PinnedMessageItem {
  channel: string;
  created: number;
  created_by: string;
  message: MessageEvent;
  type: string;
}

export interface AddPinnedMessageResponse extends BaseResponse {
  items: PinnedMessageItem[];
}

export interface RemovePinnedMessageParams {
  channel: string;
  ts: string;
  idempotencyKey: string;
}

export interface RemovePinnedMessageResponse extends BaseResponse {
  items: PinnedMessageItem[];
}

export interface GetPinnedMessagesParams {
  channel: string;
}

export interface GetPinnedMessagesResponse extends BaseResponse {
  items: PinnedMessageItem[];
}
