import { type AxiosRequestConfig, type AxiosResponse } from 'axios';

import { type MenuItemProps } from '@material-hu/components/design-system/Menu/components/MenuItem/types';

import { type FileTypes } from 'src/types/attachments';
import { type MeUser } from 'src/types/user';

export enum AudioStatus {
  Idle,
  Recording,
  Paused,
}

export type LastMessage = {
  attachments?: SendFileItem[];
  client_msg_id: string;
  text: string;
  type: string;
  subtype?: string;
  ts: string;
  username?: string;
  user?: string;
  blocks?: SystemMessages;
  highlighted_spans?: HighlightedSpan[];
  edited?: Edited;
  read_status?: ReadStatus;
  version?: number;
};

export type OtherUser = {
  id: string;
  picture_url: string;
  picture_asset_url?: string;
  first_name: string;
  last_name: string;
  employee_internal_id: string;
};

export enum HighlightedSpanType {
  USER_MENTION = 'user_mention',
  CHANNEL_MENTION = 'channel_mention',
}

export type HighlightedSpan = {
  type: HighlightedSpanType;
  start: number;
  end: number;
  user_id: number;
  full_name?: string;
};

export type HuDataChannel = {
  message_ts: string;
  message_count: number;
  picture_url?: string;
  created_at?: number;
  other_membership?: {
    id: string;
    user: {
      id: string;
      name: string;
      hu_data: HuDataConversationUser;
      deleted?: boolean;
    };
  };
  version?: number;
  mentioned?: boolean;
};

export type HuDataMessage = {
  message_ts: string;
  picture_asset_url?: string;
  version?: number;
  position?: number;
  sender_id?: number;
  highlighted_spans?: HighlightedSpan[];
  read_status?: ReadStatus;
  membership?: {
    id: string;
    last_read: string;
    unread_count: number;
    version: number;
  };
  count_unread?: boolean;
};

export type ReadStatus = {
  read_at?: number;
  received_at?: number;
};

export type ReadStateUser = {
  id: string;
  version: number;
  joined_at: number;
  last_read: string;
  properties: Record<string, any>;
  user: UserInfo;
};

export type ReadStateEntry = {
  read_at: number;
  user: ReadStateUser;
  was_in_channel_when_message_sent: boolean;
};

export type ReadStates = ReadStateEntry[];

export type MessageInfoResponse = {
  member_count_at_creation: number;
  message: ConversationMessage;
  read_states: ReadStates;
  total_read_count: number;
  response_metadata: {
    next_cursor: string;
  };
};

export type Match = {
  type: string;
  item: ConversationEventSocket;
};

export type SearchMessagesResponse = {
  matches: Match[];
  response_metadata: {
    next_cursor: string;
  };
};

export type MemberReadMessage = {
  id: string;
  pictureUrl?: string;
  userName: string;
  read_at: number;
};

export type Edited = {
  ts: string;
  user: string;
};

export enum MuteOptions {
  '1m' = '1m',
  '8h' = '8h',
  '1w' = '1w',
  ALWAYS = 'always',
}

export enum PinOptions {
  '24h' = '24h',
  '30d' = '30d',
  ALWAYS = 'always',
}
export enum NotificationType {
  ALL = 'ALL',
  MUTED = 'MUTED',
  MENTIONS = 'MENTIONS',
}

export type PropertiesConversation = {
  notification_status: {
    notification_type: NotificationType;
    until?: number | null;
  };
  pinned_at?: number | null;
  marked_unread_at?: number;
  version?: number;
};

export enum AmplitudeConversationType {
  INDIVIDUAL = 'individual',
  GROUP = 'group',
}

export enum Format {
  IMAGE = 'image',
  VIDEO = 'video',
  FILE = 'file',
  AUDIO = 'audio',
  GIF = 'gif',
}

export type SendMediaBase = {
  isLoading?: boolean;
  id: number;
  mimetype: string;
  filename: string;
  metadata: {
    format: Format;
    durationInMs?: number;
  };
};

export type SendImagesType = SendMediaBase & {
  image_url: string;
  local_image_url?: string;
  image_bytes: number;
  image_height: number;
  image_width: number;
  isNotSecure?: boolean;
};

export type SendVideosType = SendMediaBase & {
  video_url: string;
  video_html_width?: number;
  video_html_height?: number;
  size?: number;
  local_video_url?: string;
  thumb_url?: string;
  width?: number;
  height?: number;
};

export type UploadGifBody = {
  isLoading?: boolean;
  id: number;
  height: number;
  width: number;
  type: FileTypes.GIF;
  name: string;
  contentType: string;
  external_reference: {
    origin: string;
    id: string;
  };
};

export type SendGifBody = SendMediaBase & {
  isLoading?: boolean;
  id: number;
  image_bytes: number;
  image_height: number;
  image_width: number;
  external_reference: {
    origin: string;
    id: string;
  };
};

export type SendFileType = SendMediaBase & {
  url: string;
  size: number;
  file?: File;
};

export type SendAudiosType = SendFileType & {
  audio_duration_ms?: number;
};

export type PreviewFileItem = {
  isLoading?: boolean;
  id: string;
  image_url: string;
  video_url: string;
  file: false | File;
  name: string;
  mimetype: string;
  filename: string;
  metadata: {
    format: Format;
  };
};

export type SendFileItem =
  | SendImagesType
  | SendFileType
  | SendAudiosType
  | SendGifBody
  | SendVideosType
  | PreviewFileItem;

export type SendFilesList = SendFileItem[];

export type ContextUploadFiles = {
  previewFiles: PreviewFileItem[];
};

export type Channel = {
  id: string;
  created: number;
  is_im?: boolean;
  name?: string;
  num_members?: number;
  is_channel?: boolean;
  user?: string;
  is_user_deleted?: boolean;
  last_read?: string;
  local_marked_unread_ts?: string;
  latest: LastMessage;
  unread_count: number;
  unread_count_display: number;
  hu_data: HuDataChannel;
  properties: PropertiesConversation;
  purpose?: {
    value: string;
  };
};

export type ConversationMessageSocket = {
  channel_is_im: boolean;
  channel_last_msg_id: string;
  channel_ts: string;
  data: string;
  json_event: string;
  initiator: number;
  instance: number;
  msg_client_msg_id: string;
  msg_sender_fullname: string;
  msg_sender_picture: string;
  msg_version: number;
  msg_position: number;
  msg_sender_id: number;
  msg_text: string;
  msg_ts: string;
  ts: string;
  type: MessageTypeSocket;
};

export type ConversationEventSocket = {
  channel: string;
  ts: string;
  type: MessageTypeSocket;
  client_msg_id: string;
  external_id?: string;
  subtype?: string;
  user: string;
  text: string;
  username: string;
  metadata?: MetadataChanged;
  attachments: SendFileItem[];
  blocks?: SystemMessages;
  hu_data: HuDataMessage;
  edited?: Edited;
  reactions?: MessageReaction[];
};

export type JsonEventUser = {
  channel: string;
  external_id: string;
  hu_data: {
    version: number;
  };
  metadata: {
    event_payload: {
      marked_unread_at?: number;
      notification_type?: NotificationType;
      pinned_at?: number;
      version?: number;
    };
  };
  ts: string;
  type: string;
  user: string;
  username: string;
};

export type Membership = {
  id: string;
  version: number;
  user: UserInfo;
  is_admin?: boolean;
  deleted_at?: number;
  last_read: string;
  properties: PropertiesConversation;
  unread_count: number;
};

export type MetadataChanged = {
  event_payload: {
    notification_type?: NotificationType;
    pinned_at?: number;
    newName?: string;
    newPictureId?: string;
    user?: number;
    users?: string;
    newDescription?: string;
    oldDescription?: string;
    received_at?: number;
    read_at?: number;
    to_message_ts?: string;
    from_message_ts?: string;
    membership?: Membership;
    memberships?: Membership[];
    message_ts?: string;
  };
};

export enum MessageTypeSocket {
  REMOVE_MESSAGE_REACTION = 'remove',
  ADD_MESSAGE_REACTION = 'add',
  MARKED = 'channel_marked',
  LEFT = 'channel_left',
  JOINED = 'channel_joined',
  MARKED_READ = 'marked_read',
  MARKED_RECEIVED = 'marked_received',
  MESSAGE = 'message',
  REACTED = 'message_reaction',
  UPDATE = 'message_update',
  DELETED = 'message_deleted',
  CHANGED = 'channel_changed',
  CHANNEL_INFO_CHANGED = 'channel_info_changed',
  CREATED = 'channel_created',
  ADMIN_REVOKE = 'channel_admin_revoked',
  ADMIN_ADD = 'channel_admin_granted',
  PIN_REMOVED = 'remove',
  PIN_ADDED = 'add',
  PIN_MESSAGE = 'message_pin',
  MESSAGE_READ_BY_ALL = 'message_read_by_all',
}

export enum BlockType {
  JOINED = 'channel_joined',
  CREATED = 'channel_created',
  LEFT = 'channel_left',
  PICTURE_CHANGED = 'channel_picture_changed',
  RENAMED = 'channel_renamed',
  CALL_INITIALIZED = 'call_initialized',
  CALL_ENDED = 'call_ended',
  MESSAGE_REPLIED = 'message_replied',
  CHANNEL_DESCRIPTION_CHANGED = 'channel_description_changed',
  MESSAGE_FORWARDED = 'message_forwarded',
  MESSAGE_PIN_ADDED = 'message_pin_added',
}
export enum StateMessage {
  PENDING = 'PENDING',
  ERROR = 'ERROR',
  DELIVERED = 'DELIVERED',
  RECEIVED = 'RECEIVED',
  READ = 'READ',
}

export type SystemMessage =
  | BlockJoined
  | BlockCreated
  | BlockLeft
  | BlockRenamed
  | BlockPictureChanged
  | BlockInitCall
  | BlockEndCall
  | BloackMessageReplied
  | BlockChannelDescriptionChanged
  | BloackMessageForwarded
  | BlockPinAdded;

export type SystemMessages = SystemMessage[];

export type BloackMessageForwarded = {
  type: BlockType.MESSAGE_FORWARDED;
};

export type BlockPinAdded = {
  type: BlockType.MESSAGE_PIN_ADDED;
};

export type BloackMessageReplied = {
  type: BlockType.MESSAGE_REPLIED;
  message_replied_id: string;
  message_replied_client_msg_id: string;
  text?: string;
  assets: SendFilesList;
  highlighted_spans?: HighlightedSpan[];
  sender_membership: {
    id: string;
    user: {
      id: string;
      name: string;
      team_id: string;
      hu_data: HuDataConversationUser;
    };
    version: number;
  };
};

export type BlockChannelDescriptionChanged = {
  type: BlockType.CHANNEL_DESCRIPTION_CHANGED;
  new_description: string;
  old_description: string;
};

export type BlockJoined = {
  type: BlockType.JOINED;
  user_count: number;
  user_ids: number[];
  usernames: string[];
};

export type BlockCreated = {
  type: BlockType.CREATED;
};

export type BlockLeft = {
  type: BlockType.LEFT;
  user_id: number;
  username: string;
};

export type BlockRenamed = {
  type: BlockType.RENAMED;
  old_name: string;
  new_name: string;
};

export type BlockPictureChanged = {
  type: BlockType.PICTURE_CHANGED;
};

export type BlockInitCall = {
  member: {
    employee_internal_id: string;
    first_name: string;
    id: number;
    last_name: string;
    status: string;
    version: number;
  };
  type: BlockType.CALL_INITIALIZED;
};

export enum EndCallReason {
  NO_RESPONSE = 'NO_RESPONSE',
  REJECTED = 'REJECTED',
  ALL_PARTICIPANTS_LEFT = 'ALL_PARTICIPANTS_LEFT',
}

export type BlockEndCall = {
  reason: EndCallReason;
  type: BlockType.CALL_ENDED;
};

export type ConversationMessage = {
  channel: string;
  client_msg_id: string;
  attachments?: SendFileItem[];
  isLoadingFiles?: boolean;
  text?: string;
  type: MessageTypeSocket;
  subtype?: MessageTypeSocket;
  ts: string;
  user: string;
  username: string;
  state?: StateMessage;
  hu_data: HuDataMessage;
  blocks?: SystemMessages;
  edited?: Edited;
  hidden?: boolean;
  reactions: MessageReaction[];
  metadata?: MetadataChanged;
  mrkdwn?: boolean;
};

export enum StatusUser {
  ACTIVE = 'ACTIVE',
  INACTIVE = 'DEACTIVATED',
}
export type Member = {
  employee_internal_id: string;
  first_name: string;
  id: number;
  last_name: string;
  picture_url: string;
  picture_asset_url?: string;
  status: StatusUser;
  is_admin?: boolean | null;
  deleted_at?: number;
};

export type HuDataConversationUser = {
  member: Member;
};

export type ConversationUser = {
  id: string;
  name: string;
  hu_data: HuDataConversationUser;
};

export type ConversationUsersResponse = Response & {
  members: ConversationUser[];
};

export type ReactionsResponse = Response & {
  message: ConversationMessage;
};

export type ConversationsResponse = Response & {
  channels: Channel[];
};

export type ConversationsUnreadsResponse = Response & {
  channels: string[];
  unread_count: number;
  response_metadata?: {
    next_cursor?: string;
  };
};

export type ConversationMemberResponse = Response & {
  memberships: Membership[];
};

export type ConversationsOpenResponse = Response & {
  channel: Channel;
};

export type ConversationsInfoResponse = Response & {
  channel: Channel;
};

export type ConversationsEventsResponse = Response & {
  messages: ConversationMessage[];
  response_metadata?: {
    next_cursor: string;
  };
};

export type ConversationsMessagesResponse = Response & {
  messages: ConversationMessage[];
  pin_count: number;
};

export type UserInfo = {
  id: string;
  name: string;
  team_id: string;
  hu_data: HuDataConversationUser;
};

export type ConversationsUsersInfo = Response & {
  user: UserInfo;
};

type Response = {
  config?: AxiosResponse;
  status: number;
  ok: boolean;
  no_op?: boolean;
  response_metadata?: {
    next_cursor?: string;
    prev_cursor?: string;
  };
};

export type GetConversationMessagesParams = {
  channel: string;
  limit?: number;
  cursor?: string;
  types?: string;
  latest?: string;
  oldest?: string;
  direction?: 'ASC' | 'DESC';
  inclusive?: boolean;
};

export type SettingMessageType = {
  label: string;
  Icon: React.ElementType;
} & MenuItemProps;

export type EditMessageResponse = {
  channel: string;
  ts: string;
  text: string;
  message: {
    edited: {
      user: string;
      ts: string;
    };
  };
};

export type UserReactionInfo = {
  name: string;
  picture: string;
  id: number;
  emoji: string;
};

export type Reaction = {
  name: string;
  count: number;
  version: number;
};

export type MessageReaction = Reaction & {
  users: string[];
};

export type SummaryReaction = Reaction & {
  users: UserReactionInfo[];
};

export type ParamsReaction = {
  channel: string;
  ts: string;
  name: string;
  hasReacted?: boolean;
};

export type ParamsForward = {
  source_message_ts: string;
  source_channel_ts: string;
  channel_destinations: string[];
  user_destinations: number[];
};

export type ParamsConversationEvents = {
  signal?: AbortSignal;
  cursor?: string;
  latest?: string;
  oldest?: string;
  inclusive?: boolean;
  types?: string;
  unread?: boolean;
  direction?: 'ASC' | 'DESC';
  limit?: string;
};

export type AddReactionResponse = {
  ok: boolean;
  message: string;
};

export type RemoveReactionResponse = {
  ok: boolean;
  message: string;
};

export type TextPart = {
  type: 'text';
  content: string;
};

export type MentionPart = {
  type: 'mention';
  content: string;
  member: Member;
};

export type ParsedPart = TextPart | MentionPart;

export type ConversationEvents = {
  currentTs: string;
  events: ConversationMessage[];
};

export type ParamsSendMessageApi = {
  channel: string;
  text?: string;
  ulid: string;
  attachments?: SendFilesList;
  reply_ts?: string;
  audio?: {
    blob: Blob;
    duration: string;
  };
};

export type SendMessageResponseData = {
  ok: boolean;
  channel: string;
  message: ConversationMessage;
  ts: string;
};

export type CreateMessageParams = ParamsSendMessageApi & {
  messageToReply: ConversationMessage | null;
  user: MeUser;
  pictureAssetUrl?: string;
};

export type SendMessageContext = {
  client_msg_id: string;
  ts: string;
};

export type ConversationsEventsResult = {
  config?: AxiosRequestConfig;
  status: number;
  messages: ConversationMessage[];
  response_metadata:
    | ({
        next_cursor: string;
      } & {
        next_cursor: string;
      })
    | undefined;
};

export type FormValuesEditGroup = {
  picture: SendImagesType | null;
  name: string;
};

export type FetchWithRetryOptions = {
  maxRetries?: number;
  timeout?: number;
  retryDelay?: number;
};

export type TutorialViewedState = Record<string, boolean>;

export type AttachmentLoadError = Array<{
  url?: string;
  isError: boolean;
  retry: () => void;
}>;

export type SelectConversationOrUserPayload = {
  conversation?: Channel;
  user?: ConversationUser;
};

export type PinnedItem = {
  channel: string;
  created: number;
  created_by: string;
  message: ConversationMessage;
  type: string;
};

export type PinnedMessagesResponse = {
  items: PinnedItem[];
  ok: boolean;
};

export enum CursorType {
  DEFAULT = 'default',
  GRAB = 'grab',
  GRABBING = 'grabbing',
}

export type PendingReadStatus = {
  toMessageTs: string;
  readAt?: number;
  receivedAt?: number;
};
