// --- Enriched types (server→client) ---
export type UserInfo = {
  id: string;
  username: string;
  display_name: string;
  avatar_url: string;
};

export type RoomInfo = {
  id: string;
  name: string;
};

export type WorkspaceInfo = {
  id: string;
  name: string;
  avatar_url: string;
};

// --- Enums ---
export type UserPresenceStatus = "online" | "idle" | "dnd" | "offline";

// --- Reactions ---
export type ReactionGroup = {
  emoji: string;
  count: number;
  reacted_by_me: boolean;
  users: UserInfo[];
};

// --- Message Service structs ---
export type MessageNewService = {
  id: string;
  seq: number;
  room: RoomInfo;
  sender_type: string;
  sender: UserInfo;
  thread: string | null;
  in_reply_to: string | null;
  content: string;
  content_type: string;
  pinned?: boolean;
  system_type: string | null;
  metadata: Record<string, unknown>;
  thinking_content: string | null;
  thinking_is_chunked: boolean | null;
  send_at: string;
  reactions: ReactionGroup[];
};

export type MessageEditedService = {
  id: string;
  seq: number;
  room: RoomInfo;
  sender: UserInfo;
  content: string;
  edited_at: string;
};

export type MessageRevokedService = {
  id: string;
  seq: number;
  room: RoomInfo;
  revoked_by: UserInfo;
  revoked_at: string;
};

export type MessageStreamStartService = {
  message_id: string;
  room: RoomInfo;
  sse_url: string | null;
  display_name: string | null;
};

export type MessageStreamChunkService = {
  message_id: string;
  room: RoomInfo;
  seq: number;
  content: string;
  chunk_type: string;
  display_name: string | null;
};

export type MessageStreamDoneService = {
  message_id: string;
  room: RoomInfo;
  content: string;
  thinking_content: string | null;
  display_name: string | null;
  error: string | null;
};

export type MessageListService = {
  room: RoomInfo;
  messages: MessageNewService[];
  total: number;
};

// --- Member Service structs ---
export type MemberJoinedService = {
  room: RoomInfo;
  user: UserInfo;
  project_role: string | null;
  joined_at: string;
};

export type MemberRemovedService = {
  room: RoomInfo;
  user: UserInfo;
  removed_by: UserInfo;
  removed_at: string;
};

export type ReadReceiptService = {
  room: RoomInfo;
  user: UserInfo;
  last_read_seq: number;
  updated_at: string;
};

export type TypingStartService = {
  room: RoomInfo;
  user: UserInfo;
  sender_type: string;
  started_at: string;
};

export type TypingStopService = {
  room: RoomInfo;
  user: UserInfo;
  sender_type: string;
  stopped_at: string;
};

// --- Reaction Service structs ---
export type ReactionAddedService = {
  id: string;
  room: RoomInfo;
  message: string;
  user: UserInfo;
  emoji: string;
  created_at: string;
};

export type ReactionRemovedService = {
  id: string;
  room: RoomInfo;
  message: string;
  user: UserInfo;
  emoji: string;
  removed_at: string;
};

export type ReactionBatchUpdatedService = {
  room: RoomInfo;
  message: string;
  reactions: ReactionGroup[];
};

// --- Thread Service structs ---
export type ThreadCreatedService = {
  id: string;
  room: RoomInfo;
  parent: number;
  created_by: UserInfo;
  participants: unknown;
  created_at: string;
};

export type ThreadUpdatedService = {
  id: string;
  room: RoomInfo;
  last_message_at: string | null;
  last_message_preview: string | null;
  updated_at: string;
};

export type ThreadResolvedService = {
  id: string;
  room: RoomInfo;
  resolved_by: UserInfo;
  resolved_at: string;
};

export type ThreadArchivedService = {
  id: string;
  room: RoomInfo;
  archived_by: UserInfo;
  archived_at: string;
};

// --- Pin Service structs ---
export type PinAddedService = {
  room: RoomInfo;
  message: string;
  pinned_by: UserInfo;
  pinned_at: string;
};

export type PinRemovedService = {
  room: RoomInfo;
  message: string;
  removed_by: UserInfo;
  removed_at: string;
};

// --- Draft Service structs ---
export type DraftSavedService = {
  user: UserInfo;
  room: RoomInfo;
  content: string;
  saved_at: string;
};

export type DraftClearedService = {
  user: UserInfo;
  room: RoomInfo;
  cleared_at: string;
};

// --- Room Service structs ---
export type RoomCreatedService = {
  room: RoomInfo;
  workspace: WorkspaceInfo;
  public: boolean;
  category: string | null;
  created_by: UserInfo;
  created_at: string;
};

export type RoomDeletedService = {
  room: RoomInfo;
  workspace: WorkspaceInfo;
  deleted_by: UserInfo;
  deleted_at: string;
};

export type RoomRenamedService = {
  room: RoomInfo;
  workspace: WorkspaceInfo;
  old_name: string;
  new_name: string;
  renamed_by: UserInfo;
  renamed_at: string;
};

export type RoomMovedService = {
  room: RoomInfo;
  workspace: WorkspaceInfo;
  old_category: string | null;
  new_category: string | null;
  moved_by: UserInfo;
  moved_at: string;
};

export type RoomTopicUpdatedService = {
  room: RoomInfo;
  workspace: WorkspaceInfo;
  old_topic: string | null;
  new_topic: string | null;
  updated_by: UserInfo;
  updated_at: string;
};

export type RoomSettingsUpdatedService = {
  room: RoomInfo;
  workspace: WorkspaceInfo;
  slowmode_seconds: number | null;
  nsfw: boolean;
  default_auto_archive_duration: number | null;
  updated_by: UserInfo;
  updated_at: string;
};

// --- Workspace Service structs ---
export type WorkspaceRoomCreatedService = {
  workspace: WorkspaceInfo;
  room: RoomInfo;
  public: boolean;
  category: string | null;
  created_by: UserInfo;
  created_at: string;
};

export type WorkspaceRoomDeletedService = {
  workspace: WorkspaceInfo;
  room: RoomInfo;
  deleted_by: UserInfo;
  deleted_at: string;
};

// --- Category Service structs ---
export type CategoryCreatedService = {
  id: string;
  workspace: WorkspaceInfo;
  name: string;
  position: number;
  created_by: UserInfo;
  created_at: string;
};

export type CategoryUpdatedService = {
  id: string;
  workspace: WorkspaceInfo;
  name: string | null;
  position: number | null;
  updated_by: UserInfo;
  updated_at: string;
};

export type CategoryDeletedService = {
  id: string;
  workspace: WorkspaceInfo;
  deleted_by: UserInfo;
  deleted_at: string;
};

// --- Notify Service structs ---
export type NotifyCreatedService = {
  id: string;
  room: RoomInfo | null;
  workspace: WorkspaceInfo | null;
  user: UserInfo;
  notification_type: string;
  title: string;
  content: string | null;
  related_message_id: string | null;
  related_user: UserInfo | null;
  metadata: unknown;
  created_at: string;
  deep_link_url: string | null;
};

export type NotifyReadService = {
  id: string;
  user: UserInfo;
  read_at: string;
};

// --- Presence Service structs ---
export type PresenceChangedService = {
  user: UserInfo;
  workspace: WorkspaceInfo | null;
  status: UserPresenceStatus;
  last_seen_at: string | null;
};

export type CustomStatusUpdatedService = {
  user: UserInfo;
  emoji: string | null;
  text: string | null;
  expires_at: string | null;
};

// --- Invite Service structs ---
export type InviteCreatedService = {
  id: string;
  workspace: WorkspaceInfo;
  room: RoomInfo | null;
  inviter: UserInfo;
  invitee: UserInfo | null;
  code: string;
  max_uses: number | null;
  expires_at: string | null;
  created_at: string;
};

export type InviteAcceptedService = {
  id: string;
  workspace: WorkspaceInfo;
  room: RoomInfo | null;
  user: UserInfo;
  accepted_at: string;
};

// --- Ban Service structs ---
export type BannedService = {
  workspace: WorkspaceInfo;
  user: UserInfo;
  banned_by: UserInfo;
  reason: string | null;
  expires_at: string | null;
  banned_at: string;
};

export type UnbannedService = {
  workspace: WorkspaceInfo;
  user: UserInfo;
  unbanned_by: UserInfo;
  unbanned_at: string;
};

// --- Voice Service structs ---
export type VoiceChannelJoinedService = {
  room: RoomInfo;
  workspace: WorkspaceInfo | null;
  user: UserInfo;
  muted: boolean;
  deafened: boolean;
  video: boolean;
  joined_at: string;
};

export type VoiceChannelLeftService = {
  room: RoomInfo;
  workspace: WorkspaceInfo | null;
  user: UserInfo;
  left_at: string;
};

// --- Search Service structs ---
export type SearchMessageHitService = MessageNewService & {
  highlighted_content: string;
};

export type SearchResultService = {
  q: string;
  room: RoomInfo | null;
  messages: SearchMessageHitService[];
  total: number;
  took_ms: number;
};

// --- Attachment Service structs ---
export type AttachmentUploadedService = {
  id: string;
  room: RoomInfo;
  message: string;
  filename: string;
  content_type: string | null;
  size: number;
  url: string | null;
  uploaded_by: UserInfo;
  uploaded_at: string;
};

// --- Conversation state (OpenIM Conversation model) ---
export type ConversationPinnedService = {
  user: UserInfo;
  room: RoomInfo;
  pinned_at: string;
};

export type ConversationUnpinnedService = {
  user: UserInfo;
  room: RoomInfo;
  unpinned_at: string;
};

export type ConversationMutedService = {
  user: UserInfo;
  room: RoomInfo;
  muted_at: string;
};

export type ConversationUnmutedService = {
  user: UserInfo;
  room: RoomInfo;
  unmuted_at: string;
};

export type ConversationUnreadUpdatedService = {
  user: UserInfo;
  room: RoomInfo;
  last_read_seq: number;
  unread_count: number;
  updated_at: string;
};

export type ConversationSummary = {
  room: string;
  room_name: string;
  room_type: string;
  is_pinned: boolean;
  is_muted: boolean;
  notify_level: string;
  last_read_seq: number;
  max_seq: number;
  unread_count: number;
  last_read_at: string | null;
};

// --- Per-message read tracking (OpenIM MarkMsgsAsRead) ---
export type MessageReadService = {
  room: RoomInfo;
  message_id: string;
  message_seq: number;
  reader: UserInfo;
  read_at: string;
};

export type MessageReadBatchService = {
  room: RoomInfo;
  message_ids: string[];
  last_seq: number;
  reader: UserInfo;
  read_at: string;
};

export type MessageReaderEntry = {
  user: UserInfo;
  read_at: string;
};

export type MessageReadersService = {
  message_id: string;
  readers: MessageReaderEntry[];
};

// --- Message starring (Rocket.Chat starMessage) ---
export type MessageStarredService = {
  room: RoomInfo;
  message_id: string;
  message_seq: number;
  starred_by: UserInfo;
  starred_at: string;
};

export type MessageUnstarredService = {
  room: RoomInfo;
  message_id: string;
  unstarred_by: UserInfo;
  unstarred_at: string;
};

export type StarredMessageEntry = {
  message_id: string;
  room: RoomInfo;
  seq: number;
  content: string;
  content_type: string;
  sender: UserInfo;
  starred_at: string;
  sent_at: string;
};

// --- Message forwarding (OpenIM forward) ---
export type MessageForwardedService = {
  id: string;
  seq: number;
  room: RoomInfo;
  sender: UserInfo;
  content: string;
  content_type: string;
  source_room: RoomInfo;
  source_message_id: string;
  forwarded_at: string;
};

// --- Article event service structs ---
export type ArticleLikedService = {
  article_id: string;
  like_count: number;
};

export type ArticleUnlikedService = {
  article_id: string;
  like_count: number;
};

export type ArticleCommentCreatedService = {
  comment: { article: string };
  comment_count: number;
};

export type ArticleCommentDeletedService = {
  article_id: string;
  comment_count: number;
};

// --- WsOutEvent discriminated union ---
export type WsError = {
  type: "error";
  code: number;
  error: string;
  message: string;
};

export type WsOutEvent =
  | { type: "pong"; protocol_version: number }
  | WsError
  | { type: "csrf_token"; token: string }
  | { type: "room_created"; room: RoomInfo; data: RoomCreatedService }
  | { type: "room_deleted"; room: RoomInfo; data: RoomDeletedService }
  | { type: "room_renamed"; room: RoomInfo; data: RoomRenamedService }
  | { type: "room_topic_updated"; room: RoomInfo; data: RoomTopicUpdatedService }
  | { type: "room_settings_updated"; room: RoomInfo; data: RoomSettingsUpdatedService }
  | { type: "room_moved"; room: RoomInfo; data: RoomMovedService }
  | { type: "message_new"; room: RoomInfo; data: MessageNewService }
  | { type: "message_edited"; room: RoomInfo; data: MessageEditedService }
  | { type: "message_revoked"; room: RoomInfo; data: MessageRevokedService }
  | { type: "message_stream_start"; room: RoomInfo; data: MessageStreamStartService }
  | { type: "message_stream_chunk"; room: RoomInfo; data: MessageStreamChunkService }
  | { type: "message_stream_done"; room: RoomInfo; data: MessageStreamDoneService }
  | { type: "message_list"; room: RoomInfo; data: MessageListService }
  | { type: "member_joined"; room: RoomInfo; data: MemberJoinedService }
  | { type: "member_removed"; room: RoomInfo; data: MemberRemovedService }
  | { type: "read_receipt"; room: RoomInfo; data: ReadReceiptService }
  | { type: "typing_start"; room: RoomInfo; data: TypingStartService }
  | { type: "typing_stop"; room: RoomInfo; data: TypingStopService }
  | { type: "reaction_added"; room: RoomInfo; data: ReactionAddedService }
  | { type: "reaction_removed"; room: RoomInfo; data: ReactionRemovedService }
  | { type: "reaction_batch_updated"; room: RoomInfo; data: ReactionBatchUpdatedService }
  | { type: "thread_created"; room: RoomInfo; data: ThreadCreatedService }
  | { type: "thread_updated"; room: RoomInfo; data: ThreadUpdatedService }
  | { type: "thread_resolved"; room: RoomInfo; data: ThreadResolvedService }
  | { type: "thread_archived"; room: RoomInfo; data: ThreadArchivedService }
  | { type: "category_created"; workspace: WorkspaceInfo; data: CategoryCreatedService }
  | { type: "category_updated"; workspace: WorkspaceInfo; data: CategoryUpdatedService }
  | { type: "category_deleted"; workspace: WorkspaceInfo; data: CategoryDeletedService }
  | { type: "pin_added"; room: RoomInfo; data: PinAddedService }
  | { type: "pin_removed"; room: RoomInfo; data: PinRemovedService }
  | { type: "workspace_room_created"; workspace: WorkspaceInfo; data: WorkspaceRoomCreatedService }
  | { type: "workspace_room_deleted"; workspace: WorkspaceInfo; data: WorkspaceRoomDeletedService }
  | { type: "draft_saved"; room: RoomInfo; data: DraftSavedService }
  | { type: "draft_cleared"; room: RoomInfo; data: DraftClearedService }
  | { type: "search_result"; data: SearchResultService }
  | { type: "notify_created"; data: NotifyCreatedService }
  | { type: "notify_read"; data: NotifyReadService }
  | { type: "presence_changed"; data: PresenceChangedService }
  | { type: "custom_status_updated"; data: CustomStatusUpdatedService }
  | { type: "invite_created"; data: InviteCreatedService }
  | { type: "invite_accepted"; data: InviteAcceptedService }
  | { type: "attachment_uploaded"; data: AttachmentUploadedService }
  | { type: "user_banned"; data: BannedService }
  | { type: "user_unbanned"; data: UnbannedService }
  | { type: "voice_channel_joined"; data: VoiceChannelJoinedService }
  | { type: "voice_channel_left"; data: VoiceChannelLeftService }
  | { type: "conversation_pinned"; room: RoomInfo; data: ConversationPinnedService }
  | { type: "conversation_unpinned"; room: RoomInfo; data: ConversationUnpinnedService }
  | { type: "conversation_muted"; room: RoomInfo; data: ConversationMutedService }
  | { type: "conversation_unmuted"; room: RoomInfo; data: ConversationUnmutedService }
  | { type: "conversation_unread_updated"; room: RoomInfo; data: ConversationUnreadUpdatedService }
  | { type: "conversation_list"; data: ConversationSummary[] }
  | { type: "message_read"; room: RoomInfo; data: MessageReadService }
  | { type: "message_read_batch"; room: RoomInfo; data: MessageReadBatchService }
  | { type: "message_readers"; data: MessageReadersService }
  | { type: "message_starred"; room: RoomInfo; data: MessageStarredService }
  | { type: "message_unstarred"; room: RoomInfo; data: MessageUnstarredService }
  | { type: "starred_list"; data: StarredMessageEntry[] }
  | { type: "message_forwarded"; room: RoomInfo; data: MessageForwardedService }
  | { type: "article.liked"; room: RoomInfo; data: ArticleLikedService }
  | { type: "article.unliked"; room: RoomInfo; data: ArticleUnlikedService }
  | { type: "article.comment.created"; room: RoomInfo; data: ArticleCommentCreatedService }
  | { type: "article.comment.deleted"; room: RoomInfo; data: ArticleCommentDeletedService }
  | { type: "response"; request_id: string; data: unknown };