/**
 * WebSocket message protocol types for the browser client.
 * Mirrors packages/openclaw-channel-web/src/protocol.ts
 */

export type WebSocketRole = 'browser' | 'openclaw'

export type AuthMessage = {
  type: 'auth'
  role: WebSocketRole
  token: string
  sessionId?: string
}

export type AuthResultMessage = {
  type: 'auth_result'
  ok: boolean
  error?: string
  sessionId?: string
  userId?: string
  userName?: string
  lobsterName?: string
}

export type ChatMessage = {
  type: 'message'
  id: string
  sessionId: string
  from: 'user' | 'ai'
  text: string
  timestamp: number
  userId?: string
  userName?: string
  targetLobsterId?: string
}

export type AckMessage = {
  type: 'ack'
  messageId: string
  sessionId: string
}

export type TypingMessage = {
  type: 'typing'
  sessionId: string
  from: 'user' | 'ai'
  isTyping: boolean
}

export type HistoryRequestMessage = {
  type: 'history_request'
  sessionId: string
  before?: number
  limit?: number
}

export type HistoryResponseMessage = {
  type: 'history_response'
  sessionId: string
  messages: ChatMessage[]
  hasMore: boolean
}

export type PingMessage = { type: 'ping'; timestamp: number }
export type PongMessage = { type: 'pong'; timestamp: number }

export type ErrorMessage = {
  type: 'error'
  code: string
  message: string
  sessionId?: string
}

export type SessionQueueMode =
  | 'collect'
  | 'followup'
  | 'steer'
  | 'interrupt'
  | 'steer-backlog'

export type QueueStatusState = 'processing' | 'enqueued' | 'idle'

export type QueueStatusSessionEvent = {
  event: 'queue_status'
  state: QueueStatusState
  mode?: SessionQueueMode
  depth?: number
  messageId?: string
}

export type SessionEventPayload = QueueStatusSessionEvent

export type SessionEventMessage = {
  type: 'session_event'
  sessionId: string
  timestamp: number
  payload: SessionEventPayload
}

// Lobster 上/下线推送给 browser
export type LobsterStatusMessage = {
  type: 'lobster_status'
  action: 'online' | 'offline' | 'list'
  lobsters: Array<{ lobsterId: string; lobsterName: string }>
}

// Browser 上/下线推送给 openclaw
export type UserStatusMessage = {
  type: 'user_status'
  action: 'online' | 'offline'
  sessionId: string
  userId: string
  userName?: string
}

// 全局 WebSocket 动态订阅/退订会话
export type SessionJoinMessage = {
  type: 'session_join'
  sessionId: string
}

export type SessionLeaveMessage = {
  type: 'session_leave'
  sessionId: string
}

export type HistoryClearMessage = {
  type: 'history_clear'
  sessionId: string
}

export type HistoryClearResultMessage = {
  type: 'history_clear_result'
  sessionId: string
  ok: boolean
  error?: string
}

export const AVATAR_EMOJI_TYPES = [
  'default',
  'auth',
  'auth_result',
  'message',
  'typing',
  'history_request',
  'history_response',
  'ack',
  'ping',
  'pong',
  'error',
  'session_event',
  'lobster_status',
  'user_status',
  'session_join',
  'session_leave',
  'history_clear',
  'history_clear_result',
] as const

export type AvatarEmojiType = (typeof AVATAR_EMOJI_TYPES)[number]

export const AVATAR_EMOJI_RESULTS = ['success', 'failure'] as const

export type AvatarEmojiResult = (typeof AVATAR_EMOJI_RESULTS)[number]

export const AVATAR_EMOJI_RESULT_SUPPORTED_TYPES = [
  'auth_result',
  'history_clear_result',
] as const satisfies readonly AvatarEmojiType[]

export type AvatarPlaybackEvent = {
  type: AvatarEmojiType
  result?: AvatarEmojiResult
}

export type RelayMessage =
  | AuthMessage
  | AuthResultMessage
  | ChatMessage
  | AckMessage
  | TypingMessage
  | HistoryRequestMessage
  | HistoryResponseMessage
  | PingMessage
  | PongMessage
  | ErrorMessage
  | SessionEventMessage
  | LobsterStatusMessage
  | UserStatusMessage
  | SessionJoinMessage
  | SessionLeaveMessage
  | HistoryClearMessage
  | HistoryClearResultMessage

export function supportsAvatarEmojiResult(type: AvatarEmojiType): boolean {
  return (AVATAR_EMOJI_RESULT_SUPPORTED_TYPES as readonly string[]).includes(type)
}

export function toAvatarPlaybackEvent(message: RelayMessage): AvatarPlaybackEvent {
  switch (message.type) {
    case 'auth_result':
    case 'history_clear_result':
      return {
        type: message.type,
        result: message.ok ? 'success' : 'failure',
      }
    default:
      return {
        type: message.type,
      }
  }
}

export function parseRelayMessage(raw: string): RelayMessage | null {
  try {
    const parsed = JSON.parse(raw) as RelayMessage
    if (typeof parsed === 'object' && parsed !== null && 'type' in parsed) {
      return parsed
    }
    return null
  } catch {
    return null
  }
}

export function generateMessageId(): string {
  return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`
}

export const HEARTBEAT_INTERVAL_MS = 30_000
