package websocket

import (
	"encoding/json"
	"time"

	"github.com/google/uuid"
)

// INT-014: Standardized WebSocket message format

// MessageType represents the type of WebSocket message
type MessageType string

const (
	// Connection messages
	MessageTypePing  MessageType = "ping"
	MessageTypePong  MessageType = "pong"
	MessageTypeError MessageType = "error"

	// Subscription messages
	MessageTypeSubscribe    MessageType = "subscribe"
	MessageTypeUnsubscribe  MessageType = "unsubscribe"
	MessageTypeSubscribed   MessageType = "subscribed"
	MessageTypeUnsubscribed MessageType = "unsubscribed"

	// Chat messages
	MessageTypeChatMessage         MessageType = "chat_message"
	MessageTypeTyping              MessageType = "typing"
	MessageTypeReadReceipt         MessageType = "read_receipt"
	MessageTypeUserJoined          MessageType = "user_joined"
	MessageTypeUserLeft            MessageType = "user_left"
	MessageTypeConversationUpdated MessageType = "conversation_updated"

	// Playback messages
	MessageTypePlaybackState   MessageType = "playback_state"
	MessageTypePlaybackSync    MessageType = "playback_sync"
	MessageTypeAnalyticsUpdate MessageType = "analytics_update"
	MessageTypeStatsUpdate     MessageType = "stats_update"

	// Notification messages
	MessageTypeNotification MessageType = "notification"
)

// WebSocketMessage represents a standardized WebSocket message format
// INT-014: All WebSocket messages follow this structure
type WebSocketMessage struct {
	// Message identification
	ID        string `json:"id,omitempty"` // Unique message ID (UUID)
	Type      string `json:"type"`         // Message type (required)
	Timestamp string `json:"timestamp"`    // ISO 8601 timestamp (RFC3339)

	// Message data
	Data interface{} `json:"data,omitempty"` // Message payload (optional)

	// Error information (for error messages)
	Error *MessageError `json:"error,omitempty"` // Error details (for error type messages)

	// Context information
	RequestID      string `json:"request_id,omitempty"`      // Request ID for correlation
	UserID         string `json:"user_id,omitempty"`         // User ID (if applicable)
	TrackID        string `json:"track_id,omitempty"`        // Track ID (if applicable)
	ConversationID string `json:"conversation_id,omitempty"` // Conversation ID (if applicable)
}

// MessageError represents error information in WebSocket messages
type MessageError struct {
	Code    int                    `json:"code"`              // Error code
	Message string                 `json:"message"`           // Error message
	Details map[string]interface{} `json:"details,omitempty"` // Additional error details
}

// NewWebSocketMessage creates a new WebSocket message with standardized format
func NewWebSocketMessage(msgType MessageType, data interface{}) *WebSocketMessage {
	return &WebSocketMessage{
		ID:        uuid.New().String(),
		Type:      string(msgType),
		Timestamp: time.Now().UTC().Format(time.RFC3339),
		Data:      data,
	}
}

// NewErrorMessage creates a new error WebSocket message
func NewErrorMessage(code int, message string, details map[string]interface{}) *WebSocketMessage {
	return &WebSocketMessage{
		ID:        uuid.New().String(),
		Type:      string(MessageTypeError),
		Timestamp: time.Now().UTC().Format(time.RFC3339),
		Error: &MessageError{
			Code:    code,
			Message: message,
			Details: details,
		},
	}
}

// WithRequestID sets the request ID for correlation
func (m *WebSocketMessage) WithRequestID(requestID string) *WebSocketMessage {
	m.RequestID = requestID
	return m
}

// WithUserID sets the user ID
func (m *WebSocketMessage) WithUserID(userID string) *WebSocketMessage {
	m.UserID = userID
	return m
}

// WithTrackID sets the track ID
func (m *WebSocketMessage) WithTrackID(trackID string) *WebSocketMessage {
	m.TrackID = trackID
	return m
}

// WithConversationID sets the conversation ID
func (m *WebSocketMessage) WithConversationID(conversationID string) *WebSocketMessage {
	m.ConversationID = conversationID
	return m
}

// ToJSON converts the message to JSON bytes
func (m *WebSocketMessage) ToJSON() ([]byte, error) {
	return json.Marshal(m)
}

// ParseWebSocketMessage parses a JSON message into WebSocketMessage
func ParseWebSocketMessage(data []byte) (*WebSocketMessage, error) {
	var msg WebSocketMessage
	if err := json.Unmarshal(data, &msg); err != nil {
		return nil, err
	}
	return &msg, nil
}

// IsValid checks if the message has required fields
func (m *WebSocketMessage) IsValid() bool {
	return m.Type != "" && m.Timestamp != ""
}
