/**
 * WebSocket Message Types
 * FE-TYPE-006: Add type definitions for all WebSocket message types
 *
 * Comprehensive type definitions for all WebSocket messages used throughout
 * the application, including chat, streaming, player sync, and notifications.
 */

import type { User, Message, Conversation } from './api';

/**
 * Base WebSocket message structure
 * INT-014: Standardized WebSocket message format
 */
export interface BaseWebSocketMessage {
  id?: string; // Unique message ID (UUID)
  type: string; // Message type (required)
  timestamp: string; // ISO 8601 timestamp (RFC3339) - required
  data?: unknown; // Message payload (optional)
  error?: {
    code: number;
    message: string;
    details?: Record<string, unknown>;
  }; // Error information (for error messages)
  request_id?: string; // Request ID for correlation
  user_id?: string; // User ID (UUID)
  track_id?: string; // Track ID (UUID or string)
  conversation_id?: string; // Conversation ID (UUID)
}

/**
 * WebSocket message types
 */
export type WebSocketMessageType =
  | 'message'
  | 'typing'
  | 'read_receipt'
  | 'user_joined'
  | 'user_left'
  | 'conversation_updated'
  | 'error'
  | 'ping'
  | 'pong'
  | 'subscribe'
  | 'unsubscribe'
  | 'playback_sync'
  | 'playback_state'
  | 'notification';

/**
 * Generic WebSocket message
 */
export interface WebSocketMessage<T = unknown> extends BaseWebSocketMessage {
  type: WebSocketMessageType;
  data: T;
  timestamp: string;
}

/**
 * Chat WebSocket Messages
 */

/**
 * New message WebSocket event
 */
export interface ChatMessageEvent extends BaseWebSocketMessage {
  type: 'message';
  data: {
    message: Message;
    conversation_id: string;
  };
  timestamp: string;
}

/**
 * Typing indicator WebSocket event
 */
export interface TypingIndicatorEvent extends BaseWebSocketMessage {
  type: 'typing';
  data: {
    user_id: string;
    conversation_id: string;
    is_typing: boolean;
  };
  timestamp: string;
}

/**
 * Read receipt WebSocket event
 */
export interface ReadReceiptEvent extends BaseWebSocketMessage {
  type: 'read_receipt';
  data: {
    user_id: string;
    message_id: string;
    conversation_id: string;
    read_at: string;
  };
  timestamp: string;
}

/**
 * User joined conversation WebSocket event
 */
export interface UserJoinedEvent extends BaseWebSocketMessage {
  type: 'user_joined';
  data: {
    user: User;
    conversation_id: string;
  };
  timestamp: string;
}

/**
 * User left conversation WebSocket event
 */
export interface UserLeftEvent extends BaseWebSocketMessage {
  type: 'user_left';
  data: {
    user_id: string;
    conversation_id: string;
  };
  timestamp: string;
}

/**
 * Conversation updated WebSocket event
 */
export interface ConversationUpdatedEvent extends BaseWebSocketMessage {
  type: 'conversation_updated';
  data: {
    conversation: Conversation;
  };
  timestamp: string;
}

/**
 * Outgoing chat messages (client to server)
 */

/**
 * Send message request
 */
export interface SendMessageRequest extends BaseWebSocketMessage {
  type: 'message';
  data: {
    conversation_id: string;
    content: string;
    message_type?: 'text' | 'image' | 'audio' | 'file';
    attachment_url?: string;
    parent_message_id?: string;
  };
}

/**
 * Join conversation request
 */
export interface JoinConversationRequest extends BaseWebSocketMessage {
  type: 'join_conversation';
  data: {
    conversation_id: string;
  };
}

/**
 * Leave conversation request
 */
export interface LeaveConversationRequest extends BaseWebSocketMessage {
  type: 'leave_conversation';
  data: {
    conversation_id: string;
  };
}

/**
 * Start typing request
 */
export interface StartTypingRequest extends BaseWebSocketMessage {
  type: 'typing';
  data: {
    conversation_id: string;
    is_typing: true;
  };
}

/**
 * Stop typing request
 */
export interface StopTypingRequest extends BaseWebSocketMessage {
  type: 'typing';
  data: {
    conversation_id: string;
    is_typing: false;
  };
}

/**
 * Mark as read request
 */
export interface MarkAsReadRequest extends BaseWebSocketMessage {
  type: 'read_receipt';
  data: {
    conversation_id: string;
    message_id: string;
  };
}

/**
 * Add reaction request
 */
export interface AddReactionRequest extends BaseWebSocketMessage {
  type: 'add_reaction';
  data: {
    message_id: string;
    emoji: string;
  };
}

/**
 * Remove reaction request
 */
export interface RemoveReactionRequest extends BaseWebSocketMessage {
  type: 'remove_reaction';
  data: {
    message_id: string;
    emoji: string;
  };
}

/**
 * Streaming/Playback WebSocket Messages
 */

/**
 * Subscribe to track playback
 */
export interface SubscribePlaybackRequest extends BaseWebSocketMessage {
  type: 'subscribe';
  data: {
    track_id: string;
  };
}

/**
 * Unsubscribe from track playback
 */
export interface UnsubscribePlaybackRequest extends BaseWebSocketMessage {
  type: 'unsubscribe';
  data: {
    track_id: string;
  };
}

/**
 * Playback state synchronization
 */
export interface PlaybackStateEvent extends BaseWebSocketMessage {
  type: 'playback_state';
  data: {
    track_id: string;
    user_id: string;
    position: number; // Current playback position in seconds
    is_playing: boolean;
    volume: number;
    timestamp: string;
  };
  timestamp: string;
}

/**
 * Playback sync request
 */
export interface PlaybackSyncRequest extends BaseWebSocketMessage {
  type: 'playback_sync';
  data: {
    track_id: string;
    position: number;
    is_playing: boolean;
    volume?: number;
  };
}

/**
 * Notification WebSocket Messages
 */

/**
 * Notification event
 */
export interface NotificationEvent extends BaseWebSocketMessage {
  type: 'notification';
  data: {
    id: string;
    user_id: string;
    type:
      | 'new_message'
      | 'track_uploaded'
      | 'user_mentioned'
      | 'system'
      | 'playlist_shared';
    content: string;
    link?: string;
    read: boolean;
    created_at: string;
  };
  timestamp: string;
}

/**
 * Error WebSocket Messages
 */

/**
 * WebSocket error event
 */
export interface WebSocketErrorEvent extends BaseWebSocketMessage {
  type: 'error';
  data: {
    code: number;
    message: string;
    details?: Record<string, unknown>;
  };
  timestamp: string;
}

/**
 * Ping/Pong Messages
 */

/**
 * Ping message (client to server)
 */
export interface PingMessage extends BaseWebSocketMessage {
  type: 'ping';
  data?: {
    timestamp: string;
  };
}

/**
 * Pong message (server to client)
 */
export interface PongMessage extends BaseWebSocketMessage {
  type: 'pong';
  data?: {
    timestamp: string;
  };
  timestamp: string;
}

/**
 * Union type for all incoming WebSocket messages (server to client)
 */
export type IncomingWebSocketMessage =
  | ChatMessageEvent
  | TypingIndicatorEvent
  | ReadReceiptEvent
  | UserJoinedEvent
  | UserLeftEvent
  | ConversationUpdatedEvent
  | PlaybackStateEvent
  | NotificationEvent
  | WebSocketErrorEvent
  | PongMessage;

/**
 * Union type for all outgoing WebSocket messages (client to server)
 */
export type OutgoingWebSocketMessage =
  | SendMessageRequest
  | JoinConversationRequest
  | LeaveConversationRequest
  | StartTypingRequest
  | StopTypingRequest
  | MarkAsReadRequest
  | AddReactionRequest
  | RemoveReactionRequest
  | SubscribePlaybackRequest
  | UnsubscribePlaybackRequest
  | PlaybackSyncRequest
  | PingMessage;

/**
 * Type guard for incoming WebSocket messages
 */
export function isIncomingWebSocketMessage(
  message: unknown,
): message is IncomingWebSocketMessage {
  return (
    typeof message === 'object' &&
    message !== null &&
    'type' in message &&
    typeof (message as any).type === 'string'
  );
}

/**
 * Type guard for outgoing WebSocket messages
 */
export function isOutgoingWebSocketMessage(
  message: unknown,
): message is OutgoingWebSocketMessage {
  return (
    typeof message === 'object' &&
    message !== null &&
    'type' in message &&
    typeof (message as any).type === 'string'
  );
}

/**
 * Type guard for specific message type
 */
export function isWebSocketMessageType<T extends WebSocketMessageType>(
  message: unknown,
  type: T,
): message is IncomingWebSocketMessage & { type: T } {
  return (
    isIncomingWebSocketMessage(message) &&
    (message as IncomingWebSocketMessage).type === type
  );
}
