/** IM 内容类型枚举（对齐后端 ImContentTypeEnum） */
export const ImContentType = {
  // ========== 用户聊天消息（101-105 直接复用 OpenIM 段位编号） ==========
  TEXT: 101, // 文本（对应 OpenIM Text=101）
  IMAGE: 102, // 图片（对应 OpenIM Picture=102）
  VOICE: 103, // 语音（对应 OpenIM Sound=103）
  VIDEO: 104, // 视频（对应 OpenIM Video=104）
  FILE: 105, // 文件（对应 OpenIM File=105）
  MERGE: 107, // 合并转发（对应 OpenIM Merger=107；payload 内嵌完整快照）
  CARD: 108, // 名片（对应 OpenIM Card=108）
  FACE: 115, // 表情贴图（对应 OpenIM Face=115；Unicode emoji 仍走 TEXT）
  // ========== 频道消息扩展段（125+；OpenIM 122 之后未占用，作为频道 / 公众号类消息扩展） ==========
  MATERIAL: 125, // 频道素材（图文卡片：title + coverUrl + summary + url；详情拉 get-content）
  // ========== 信号类（2101 / 2200 直接复用 OpenIM 段位编号；2201 自有扩展） ==========
  RECALL: 2101, // 撤回（对应 OpenIM RevokeNotification=2101）
  RECEIPT: 2200, // 回执（对应 OpenIM HasReadReceipt=2200）
  READ: 2201, // 已读（多端同步，OpenIM 无对应；自有扩展）
  // ========== 实时通话信令（1601-1605 段位与 OpenIM 对齐；1610+ 自有扩展） ==========
  RTC_CALL: 1601, // 通话信令统一入口（对应 OpenIM SignalingNotification=1601）
  RTC_PARTICIPANT_CONNECTED: 1602, // 通话参与者加入（对应 OpenIM RoomParticipantsConnectedNotification=1602）
  RTC_PARTICIPANT_DISCONNECTED: 1603, // 通话参与者离开（对应 OpenIM RoomParticipantsDisconnectedNotification=1603）
  // 1604-1609 OpenIM 已用 / 留作扩展，本系统暂不使用
  RTC_CALL_START: 1610, // 通话开始（自有扩展，OpenIM 无；仅群聊；与 END 两段式配对）
  RTC_CALL_END: 1611, // 通话结束（自有扩展，OpenIM 无；私聊 / 群聊）
  // ========== 好友通知（1201-1210 直接复用 OpenIM 段位编号） ==========
  FRIEND_REQUEST_APPROVED: 1201, // 好友申请被同意
  FRIEND_REQUEST_REJECTED: 1202, // 好友申请被拒绝
  FRIEND_REQUEST_RECEIVED: 1203, // 收到新的好友申请
  FRIEND_ADD: 1204, // 新增好友（双方建立关系）
  FRIEND_DELETE: 1205, // 好友被删除
  // 1206 对应 OpenIM FriendRemarkSetNotification；本系统并入 FRIEND_UPDATE(1210) 统一推送，单一字段变更不再独立通道
  FRIEND_BLOCK: 1207, // 加入黑名单
  FRIEND_UNBLOCK: 1208, // 移出黑名单
  FRIEND_INFO_UPDATED: 1209, // 好友资料变更（昵称 / 头像）
  FRIEND_UPDATE: 1210, // 好友信息批量更新（silent / pinned）
  // ========== 群事件（1501-1520 直接复用 OpenIM 段位编号；1530+ 自有扩展段） ==========
  GROUP_CREATE: 1501, // 群创建
  GROUP_INFO_UPDATE: 1502, // 群信息变更（NAME / NOTICE 之外字段兜底）
  GROUP_REQUEST_RECEIVED: 1503, // 收到新的入群申请（私聊定向推送给群主 + 全部管理员）
  GROUP_MEMBER_QUIT: 1504, // 成员退群
  GROUP_REQUEST_APPROVED: 1505, // 入群申请被同意（私聊推给申请人 + 群主 + 全部管理员）
  GROUP_REQUEST_REJECTED: 1506, // 入群申请被拒绝（同上）
  GROUP_OWNER_TRANSFER: 1507, // 群主转让
  GROUP_MEMBER_KICK: 1508, // 成员被移出
  GROUP_MEMBER_INVITE: 1509, // 成员加入
  GROUP_MEMBER_ENTER: 1510, // 自由进群（FREE 模式或申请通过后；全员广播）
  GROUP_DISSOLVE: 1511, // 群解散
  GROUP_MEMBER_MUTED: 1512, // 单成员禁言
  GROUP_MEMBER_CANCEL_MUTED: 1513, // 单成员取消禁言
  GROUP_MUTED: 1514, // 全群禁言
  GROUP_CANCEL_MUTED: 1515, // 全群取消禁言
  GROUP_MEMBER_NICKNAME_UPDATE: 1516, // 成员昵称变更（窄化到 displayUserName）
  GROUP_ADMIN_ADD: 1517, // 添加管理员
  GROUP_ADMIN_REMOVE: 1518, // 撤销管理员
  GROUP_NOTICE_UPDATE: 1519, // 群公告变更
  GROUP_NAME_UPDATE: 1520, // 群名变更
  // ========== 自有扩展段（1530+，OpenIM 1500-1520 段位无对应物） ==========
  GROUP_MEMBER_SETTING_UPDATE: 1530, // 群成员个人设置变更：silent / groupRemark 个人多端同步
  GROUP_MESSAGE_PIN: 1531, // 群消息置顶（自有扩展，OpenIM 无）
  GROUP_MESSAGE_UNPIN: 1532, // 群消息取消置顶（自有扩展，OpenIM 无）
  GROUP_BANNED: 1533 // 群封禁变更（自有扩展，OpenIM 无）
} as const

/** 判断是否「群广播事件」：[GROUP_CREATE, GROUP_BANNED] 段位都算，仅 GROUP_MEMBER_SETTING_UPDATE 是个人信号排除 */
export function isGroupNotification(type: number): boolean {
  return (
    type >= ImContentType.GROUP_CREATE &&
    type <= ImContentType.GROUP_BANNED &&
    type !== ImContentType.GROUP_MEMBER_SETTING_UPDATE
  )
}

/** 判断是否「好友通知事件」：1201-1210 段位 */
export function isFriendNotification(type: number): boolean {
  return type >= ImContentType.FRIEND_REQUEST_APPROVED && type <= ImContentType.FRIEND_UPDATE
}

/** 判断是否「加群申请通知事件」：1503/1505/1506 */
export function isGroupRequestNotification(type: number): boolean {
  return (
    type === ImContentType.GROUP_REQUEST_RECEIVED ||
    type === ImContentType.GROUP_REQUEST_APPROVED ||
    type === ImContentType.GROUP_REQUEST_REJECTED
  )
}

/** 判断是否「会话内的好友事件气泡」：FRIEND_ADD / FRIEND_DELETE 直接渲染成灰色提示，与群事件同处理 */
export function isFriendChatTip(type: number): boolean {
  return type === ImContentType.FRIEND_ADD || type === ImContentType.FRIEND_DELETE
}

/** 判断是否「会话内的通话事件气泡」：RTC_CALL_START / RTC_CALL_END 渲染成灰色提示 */
export function isRtcCallTip(type: number): boolean {
  return type === ImContentType.RTC_CALL_START || type === ImContentType.RTC_CALL_END
}

/**
 * IM 普通内容类型集合（normal vs event 二分；与后端 ImContentTypeEnum.normal 字段语义一致）
 *
 * 这个集合在多处被复用，新增类型前先确认所有副作用都符合预期：
 * 1. 后端发送入口校验（Im{Private,Group}MessageSendReqVO.isNormalType）—— 用户发送的内容类型必须 normal=true
 * 2. 前端接收侧未读 / 提示音（websocketStore）—— normal 消息计入会话未读数 + 触发声音
 * 3. 前端会话列表 lastType / @ 标签（ConversationItem）—— 只有 normal 才算「最后一条聊天消息」
 * 4. 前端群消息置顶菜单（message-item.vue 的 canPin）—— normal 才允许群主 / 管理员置顶
 *
 * 名片（CARD）/ 表情（FACE）都是「用户主动发的聊天消息」，1/2/3 都符合预期；4 同时放开 = 群主可置顶，语义合理
 */
const ImContentTypeNormals = new Set<number>([
  ImContentType.CARD,
  ImContentType.FACE,
  ImContentType.FILE,
  ImContentType.IMAGE,
  ImContentType.MATERIAL, // 频道素材计入未读数 + 进会话列表
  ImContentType.MERGE,
  ImContentType.TEXT,
  ImContentType.VIDEO,
  ImContentType.VOICE
])

/** 判断是否"普通消息" */
export function isNormalMessage(type: number): boolean {
  return ImContentTypeNormals.has(type)
}

/** IM 媒体内容类型集合：发送依赖本地 File 上传，刷新后 _localFile 丢失即不可恢复 */
const ImContentTypeMedia = new Set<number>([
  ImContentType.FILE,
  ImContentType.IMAGE,
  ImContentType.VIDEO,
  ImContentType.VOICE
])

/** 判断是否「媒体消息」：图片 / 文件 / 语音 / 视频 */
export function isMediaMessageType(type: number): boolean {
  return ImContentTypeMedia.has(type)
}

/**
 * IM 消息状态枚举（对齐后端 ImMessageStatusEnum，前端扩展 SENDING + FAILED）
 *
 * 生命周期：FAILED(-2) → SENDING(-1) → NORMAL(0) → RECALL(2)
 */
export const ImMessageStatus = {
  FAILED: -2, // 发送失败（前端独有）
  SENDING: -1, // 发送中（前端独有）
  NORMAL: 0, // 正常
  RECALL: 2 // 已撤回
} as const

/** IM 会话类型枚举 */
export const ImConversationType = {
  NONE: 0, // 无会话
  PRIVATE: 1, // 私聊
  GROUP: 2, // 群聊
  CHANNEL: 3 // 频道 / 公众号
} as const

/** ImConversationType 取值（用于消息 payload 字段类型收窄） */
export type ImConversationTypeValue = (typeof ImConversationType)[keyof typeof ImConversationType]

/** 是否私聊会话；同时收窄类型 */
export function isPrivateConversation(type: number | undefined): boolean {
  return type === ImConversationType.PRIVATE
}

/** 是否群聊会话；同时收窄类型 */
export function isGroupConversation(type: number | undefined): boolean {
  return type === ImConversationType.GROUP
}

/** 是否频道会话；同时收窄类型 */
export function isChannelConversation(type: number | undefined): boolean {
  return type === ImConversationType.CHANNEL
}

/** IM 通话媒体类型（对齐后端 ImRtcCallMediaTypeEnum） */
export const ImRtcCallMediaType = {
  VOICE: 1,
  VIDEO: 2
} as const

/** IM 通话状态（对齐后端 ImRtcCallStatusEnum） */
export const ImRtcCallStatus = {
  CREATED: 10, // 创建：私聊等被叫接听；群聊发起人已进房等其他人加入
  RUNNING: 20, // 进行中：第一个非发起人接通后进入
  ENDED: 30 // 已结束
} as const

/** IM 通话结束原因（对齐后端 ImRtcCallEndReasonEnum） */
export const ImRtcCallEndReason = {
  HANGUP: 1, // 接通后任一方主动挂断
  REJECT: 2, // 被叫接通前点拒接
  CANCEL: 3, // 主叫接通前主动取消
  NO_ANSWER: 4, // 振铃超时未接通
  BUSY: 5, // 私聊呼叫时对方正忙
  ERROR: 9 // 网络中断 / 设备失败
} as const

/** ImRtcCallEndReason 取值类型 */
export type ImRtcCallEndReasonValue = (typeof ImRtcCallEndReason)[keyof typeof ImRtcCallEndReason]

/** IM 通话参与者状态（对齐后端 ImRtcParticipantStatusEnum）；同时作为 RTC_CALL 信令 status 字段取值 */
export const ImRtcParticipantStatus = {
  INVITING: 10, // 来电邀请
  JOINED: 20, // 接听 / 已加入
  REJECTED: 30, // 拒接
  NO_ANSWER: 40, // 主叫取消，被邀请方未应答
  LEFT: 50 // 挂断离开
} as const

/** ImRtcParticipantStatus 取值类型 */
export type ImRtcParticipantStatusValue =
  (typeof ImRtcParticipantStatus)[keyof typeof ImRtcParticipantStatus]

/**
 * IM 通话 UI 阶段；前端独有，用于驱动 inviting / incoming / running 三种弹窗切换；
 * 跟后端 ImRtcCallStatus 不是 1:1 映射，stage 多了「自己是主叫还是被叫」的角色维度
 */
export const ImRtcCallStage = {
  IDLE: 'idle', // 空闲；后端无对应（本端无活跃通话）
  INVITING: 'inviting', // 主叫等待对方接受；对应后端 ImRtcCallStatus.CREATED（自己是主叫）
  INCOMING: 'incoming', // 被叫来电响铃；对应后端 ImRtcCallStatus.CREATED（自己是被叫）
  RUNNING: 'running' // 通话中；对应后端 ImRtcCallStatus.RUNNING
} as const

/** ImRtcCallStage 取值类型 */
export type ImRtcCallStageValue = (typeof ImRtcCallStage)[keyof typeof ImRtcCallStage]

/** IM WebSocket 外层帧类型 */
export const ImWebSocketMessageType = {
  NOTIFICATION: 'im-notification' // IM 通知
} as const

/** IM 消息回执状态枚举（对齐后端 ImMessageReceiptStatusEnum） */
export const ImMessageReceiptStatus = {
  NO_RECEIPT: 0, // 不需要回执
  PENDING: 1, // 待完成
  DONE: 2 // 已完成
} as const

/** 群成员角色（对齐后端 ImGroupMemberRoleEnum） */
export const ImGroupMemberRole = {
  OWNER: 1, // 群主
  ADMIN: 2, // 管理员
  NORMAL: 3 // 普通成员
} as const

/** 加群来源（对齐后端 ImGroupAddSourceEnum） */
export const ImGroupAddSource = {
  SEARCH: 1, // 搜索
  INVITE: 2, // 邀请
  QR_CODE: 3, // 扫码
  SHARE_LINK: 4 // 分享链接
} as const

/** 加群申请处理结果（对齐后端 ImGroupRequestHandleResultEnum） */
export const ImGroupRequestHandleResult = {
  UNHANDLED: 0, // 未处理
  AGREED: 1, // 同意
  REFUSED: 2 // 拒绝
} as const

/** 好友添加来源（对齐后端 ImFriendAddSourceEnum） */
export const ImFriendAddSource = {
  SEARCH: 1, // 搜索
  GROUP: 2, // 群聊
  QR_CODE: 3, // 扫码
  CARD: 4 // 名片
} as const

/** 好友申请处理结果（对齐后端 ImFriendRequestHandleResultEnum） */
export const ImFriendRequestHandleResult = {
  UNHANDLED: 0, // 未处理
  AGREED: 1, // 同意
  REFUSED: 2 // 拒绝
} as const

/**
 * @全体成员 的特殊 userId 标识：atUserIds 中包含 -1 表示 @ 全体成员
 *
 * 与后端约定：群消息 atUserIds 数组里出现 -1 时，所有成员都收到提醒
 * MentionPicker 渲染虚拟项 + conversationStore.applyAt 判定 atAll 都靠这个值
 */
export const IM_AT_ALL_USER_ID = -1

/** @全体成员 的展示名（对齐微信 PC） */
export const IM_AT_ALL_NICKNAME = '所有人'

/** 转发模式：SINGLE 逐条原样转 / MERGE 打包成 MergeMessage */
export const ImForwardMode = {
  SINGLE: 'single',
  MERGE: 'merge'
} as const

/** ImForwardMode 取值类型 */
export type ImForwardModeValue = (typeof ImForwardMode)[keyof typeof ImForwardMode]
