export interface WsRequest {
  type: 'request';
  request_id: string;
  action: WsAction;
  params?: WsRequestParams;
}

export type WsAction =
  | 'room.list'
  | 'room.get'
  | 'room.create'
  | 'room.update'
  | 'room.delete'
  | 'category.list'
  | 'category.create'
  | 'category.update'
  | 'category.delete'
  | 'message.list'
  | 'message.create'
  | 'message.update'
  | 'message.revoke'
  | 'message.get'
  | 'member.list'
  | 'member.add'
  | 'member.remove'
  | 'member.leave'
  | 'member.set_read_seq'
  | 'member.update_role'
  | 'pin.list'
  | 'pin.add'
  | 'pin.remove'
  | 'thread.list'
  | 'thread.create'
  | 'thread.messages'
  | 'reaction.add'
  | 'reaction.remove'
  | 'reaction.get'
  | 'message.search'
  | 'message.edit_history'
  | 'ai.list'
  | 'ai.upsert'
  | 'ai.delete'
  | 'notification.list'
  | 'notification.mark_read'
  | 'notification.mark_all_read'
  | 'notification.archive'
  | 'mention.list'
  | 'mention.read_all'
  | 'room.subscribe'
  | 'room.unsubscribe'
  | 'project.subscribe'
  | 'project.unsubscribe'
  | 'reaction.list_batch'
  | 'typing.start'
  | 'typing.stop';

export interface WsRequestParams {
  project_name?: string;
  room_id?: string;
  message_id?: string;
  user_id?: string;
  category_id?: string;
  thread_id?: string;
  model_id?: string;
  notification_id?: string;
  emoji?: string;
  only_public?: boolean;
  only_unread?: boolean;
  limit?: number;
  offset?: number;
  before_seq?: number;
  after_seq?: number;
  room_name?: string;
  room_public?: boolean;
  room_category?: string;
  content?: string;
  content_type?: string;
  in_reply_to?: string;
  parent_seq?: number;
  role?: string;
  last_read_seq?: number;
  name?: string;
  position?: number;
  model?: string;
  model_version?: string;
  history_limit?: number;
  system_prompt?: string;
  temperature?: number;
  max_tokens?: number;
  use_exact?: boolean;
  think?: boolean;
  stream?: boolean;
  min_score?: number;
  query?: string;
  message_ids?: string[];
  attachment_ids?: string[];
  typing?: string;
}

export interface WsResponse {
  type: 'response';
  request_id: string;
  action: string;
  data?: WsResponseData;
  error?: WsErrorInfo | null;
}

export interface WsErrorInfo {
  code: number;
  error: string;
  message: string;
}

/** 响应数据类型 */
export type WsResponseData =
  | boolean
  | number
  | RoomResponse
  | RoomResponse[]
  | RoomCategoryResponse
  | RoomCategoryResponse[]
  | RoomMessageResponse
  | RoomMessageListResponse
  | RoomMemberResponse
  | RoomMemberResponse[]
  | PinResponseData
  | PinResponseData[]
  | RoomThreadResponse
  | RoomThreadResponse[]
  | ReactionListData
  | ReactionListData[]
  | SearchResultData
  | MessageEditHistoryResponse
  | AiConfigData
  | AiConfigData[]
  | NotificationListData
  | MentionListData
  | SubscribeData
  | UserInfo[]
  | null;

export interface TypingStartPayload {
  room_id: string;
  user_id: string;
  username: string;
  avatar_url?: string;
  /** "user" or "ai". Defaults to "user". */
  sender_type?: string;
}

export interface TypingStopPayload {
  room_id: string;
  user_id: string;
}

export interface WsEvent {
  type: 'event';
  event: string;
  room_id?: string | null;
  project_id?: string | null;
  data?: unknown;
  error?: string | null;
}

/** Maps backend event string to typed event. Only room-relevant events are typed. */
export type WsEventPayload =
  | { type: 'room_message'; data: RoomMessagePayload }
  | { type: 'project_event'; data: ProjectEventPayload }
  | { type: 'ai_stream_chunk'; data: AiStreamChunkPayload }
  | { type: 'room_reaction_updated'; data: RoomReactionUpdatedPayload }
  | { type: 'message_edited'; data: MessageEditedPayload }
  | { type: 'message_revoked'; data: MessageRevokedPayload }
  | { type: 'message_pinned'; data: MessagePinnedPayload }
  | { type: 'message_unpinned'; data: MessageUnpinnedPayload }
  | { type: 'user_presence'; data: UserPresencePayload }
  | { type: 'typing_start'; data: TypingStartPayload }
  | { type: 'typing_stop'; data: TypingStopPayload }
  | { type: 'notification_created'; data: NotificationCreatedPayload }
  | { type: string; data: unknown }; // catch-all for unknown events

/** Payload for real-time notification push via WebSocket. */
export interface NotificationCreatedPayload {
  notification: NotificationData;
  /** URL to navigate to for this notification (e.g. /project/x/issues/42) */
  deep_link_url?: string;
}

export interface RoomMessagePayload {
  id: string;
  room_id: string;
  sender_type: string;
  sender_id?: string;
  thread_id?: string;
  content: string;
  content_type: string;
  /** Accumulated AI reasoning/thinking text. */
  thinking_content?: string;
  send_at: string;
  seq: number;
  display_name?: string;
  /** Present when this event carries reaction updates for the message */
  reactions?: ReactionItem[];
}

export interface ProjectEventPayload {
  event_type: string;
  project_id: string;
  room_id?: string;
  category_id?: string;
  message_id?: string;
  seq?: number;
  timestamp: string;
}

export interface AiStreamChunkPayload {
  message_id: string;
  room_id: string;
  content: string;
  done: boolean;
  error?: string;
  /** Human-readable AI model name for display (e.g. "Claude 3.5 Sonnet"). */
  display_name?: string;
  /** What kind of content: "thinking", "answer", "tool_call", "tool_result". */
  chunk_type?: string;
}

export interface RoomResponse {
  id: string;
  project: string;
  room_name: string;
  public: boolean;
  category?: string;
  created_by: string;
  created_at: string;
  last_msg_at: string;
  unread_count: number;
}

export interface RoomCategoryResponse {
  id: string;
  project: string;
  name: string;
  position: number;
  created_by: string;
  created_at: string;
}

export interface RoomMessageResponse {
  id: string;
  seq: number;
  room: string;
  sender_type: string;
  sender_id?: string;
  display_name?: string;
  thread?: string;
  in_reply_to?: string;
  content: string;
  content_type: string;
  edited_at?: string;
  send_at: string;
  revoked?: string;
  revoked_by?: string;
}

export interface RoomMessageListResponse {
  messages: RoomMessageResponse[];
  total: number;
}

export interface RoomMemberResponse {
  room: string;
  user: string;
  user_info?: UserInfo;
  role: string;
  first_msg_in?: string;
  joined_at?: string;
  last_read_seq?: number;
  do_not_disturb: boolean;
  dnd_start_hour?: number;
  dnd_end_hour?: number;
}

export interface UserInfo {
  uid: string;
  username: string;
  avatar_url?: string;
}

export interface PinResponseData {
  room: string;
  message: string;
  pinned_by: string;
  pinned_at: string;
  message_data?: RoomMessageResponse;
}

export interface RoomThreadResponse {
  id: string;
  room: string;
  parent: number;
  created_by: string;
  participants: unknown;
  last_message_at: string;
  last_message_preview?: string;
  created_at: string;
  updated_at: string;
}

export interface ReactionItem {
  emoji: string;
  count: number;
  reacted_by_me: boolean;
  users: string[];
}

export interface ReactionListData {
  message_id: string;
  reactions: ReactionItem[];
}

export interface RoomReactionUpdatedPayload {
  room_id: string;
  message_id: string;
  reactions: ReactionItem[];
}

export interface MessageEditedPayload {
  message_id: string;
  room_id: string;
  edited_at: string;
}

export interface MessageRevokedPayload {
  message_id: string;
  room_id: string;
  revoked_at: string;
  revoked_by: string;
}

export interface MessagePinnedPayload {
  message_id: string;
  room_id: string;
  pinned_by: string;
  pinned_at: string;
}

export interface MessageUnpinnedPayload {
  message_id: string;
  room_id: string;
}

export interface UserPresencePayload {
  user_id: string;
  room_id: string;
  status: 'online' | 'away' | 'dnd' | 'offline';
}

export interface SearchResultData {
  messages: RoomMessageResponse[];
  total: number;
}

export interface EditHistoryEntry {
  old_content: string;
  new_content: string;
  edited_at: string;
}

export interface MessageEditHistoryResponse {
  message_id: string;
  history: EditHistoryEntry[];
  total_edits: number;
}

export interface AiConfigData {
  room: string;
  model: string;
  model_name?: string;
  version?: string;
  call_count: number;
  last_call_at?: string;
  history_limit?: number;
  system_prompt?: string;
  temperature?: number;
  max_tokens?: number;
  use_exact: boolean;
  think: boolean;
  stream: boolean;
  min_score?: number;
  created_at: string;
  updated_at: string;
}

export interface NotificationData {
  id: string;
  room?: string;
  project?: string;
  user_id?: string;
  user_info?: UserInfo;
  notification_type: string;
  title: string;
  content?: string;
  related_message_id?: string;
  related_user_id?: string;
  related_room_id?: string;
  is_read: boolean;
  is_archived: boolean;
  created_at: string;
  read_at?: string;
  expires_at?: string;
}

export interface NotificationListData {
  notifications: NotificationData[];
  total: number;
  unread_count: number;
}

export interface MentionListData {
  mentions: MentionData[];
}

export interface MentionData {
  message_id: string;
  mentioned_by: string;
  mentioned_by_name: string;
  content_preview: string;
  room_id: string;
  room_name: string;
  created_at: string;
}

export interface SubscribeData {
  room_id?: string;
  project_id?: string;
}

export type WsInMessage = WsResponse | WsEvent | WsErrorMessage;

export interface WsErrorMessage {
  type: 'error';
  error: string;
  message?: string;
}
