package websocketspec

import (
	"encoding/json"
	"time"

	"github.com/bitechdev/ResolveSpec/pkg/common"
)

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

const (
	// MessageTypeRequest is a client request message
	MessageTypeRequest MessageType = "request"
	// MessageTypeResponse is a server response message
	MessageTypeResponse MessageType = "response"
	// MessageTypeNotification is a server-initiated notification
	MessageTypeNotification MessageType = "notification"
	// MessageTypeSubscription is a subscription control message
	MessageTypeSubscription MessageType = "subscription"
	// MessageTypeError is an error message
	MessageTypeError MessageType = "error"
	// MessageTypePing is a keepalive ping message
	MessageTypePing MessageType = "ping"
	// MessageTypePong is a keepalive pong response
	MessageTypePong MessageType = "pong"
)

// OperationType represents the operation to perform
type OperationType string

const (
	// OperationRead retrieves records
	OperationRead OperationType = "read"
	// OperationCreate creates a new record
	OperationCreate OperationType = "create"
	// OperationUpdate updates an existing record
	OperationUpdate OperationType = "update"
	// OperationDelete deletes a record
	OperationDelete OperationType = "delete"
	// OperationSubscribe subscribes to entity changes
	OperationSubscribe OperationType = "subscribe"
	// OperationUnsubscribe unsubscribes from entity changes
	OperationUnsubscribe OperationType = "unsubscribe"
	// OperationMeta retrieves metadata about an entity
	OperationMeta OperationType = "meta"
)

// Message represents a WebSocket message
type Message struct {
	// ID is a unique identifier for request/response correlation
	ID string `json:"id,omitempty"`

	// Type is the message type
	Type MessageType `json:"type"`

	// Operation is the operation to perform
	Operation OperationType `json:"operation,omitempty"`

	// Schema is the database schema name
	Schema string `json:"schema,omitempty"`

	// Entity is the table/model name
	Entity string `json:"entity,omitempty"`

	// RecordID is the ID for single-record operations (update, delete, read by ID)
	RecordID string `json:"record_id,omitempty"`

	// Data contains the request/response payload
	Data interface{} `json:"data,omitempty"`

	// Options contains query options (filters, sorting, pagination, etc.)
	Options *common.RequestOptions `json:"options,omitempty"`

	// SubscriptionID is the subscription identifier
	SubscriptionID string `json:"subscription_id,omitempty"`

	// Success indicates if the operation was successful
	Success bool `json:"success,omitempty"`

	// Error contains error information
	Error *ErrorInfo `json:"error,omitempty"`

	// Metadata contains additional response metadata
	Metadata map[string]interface{} `json:"metadata,omitempty"`

	// Timestamp is when the message was created
	Timestamp time.Time `json:"timestamp,omitempty"`
}

// ErrorInfo contains error details
type ErrorInfo struct {
	// Code is the error code
	Code string `json:"code"`

	// Message is a human-readable error message
	Message string `json:"message"`

	// Details contains additional error context
	Details map[string]interface{} `json:"details,omitempty"`

	// SQL is the query that caused the error, populated for database errors
	SQL string `json:"sql,omitempty"`
}

// RequestMessage represents a client request
type RequestMessage struct {
	ID        string                 `json:"id"`
	Type      MessageType            `json:"type"`
	Operation OperationType          `json:"operation"`
	Schema    string                 `json:"schema,omitempty"`
	Entity    string                 `json:"entity"`
	RecordID  string                 `json:"record_id,omitempty"`
	Data      interface{}            `json:"data,omitempty"`
	Options   *common.RequestOptions `json:"options,omitempty"`
}

// ResponseMessage represents a server response
type ResponseMessage struct {
	ID        string                 `json:"id"`
	Type      MessageType            `json:"type"`
	Success   bool                   `json:"success"`
	Data      interface{}            `json:"data,omitempty"`
	Error     *ErrorInfo             `json:"error,omitempty"`
	Metadata  map[string]interface{} `json:"metadata,omitempty"`
	Timestamp time.Time              `json:"timestamp"`
}

// NotificationMessage represents a server-initiated notification
type NotificationMessage struct {
	Type           MessageType   `json:"type"`
	Operation      OperationType `json:"operation"`
	SubscriptionID string        `json:"subscription_id"`
	Schema         string        `json:"schema"`
	Entity         string        `json:"entity"`
	Data           interface{}   `json:"data"`
	Timestamp      time.Time     `json:"timestamp"`
}

// SubscriptionMessage represents a subscription control message
type SubscriptionMessage struct {
	ID             string                 `json:"id"`
	Type           MessageType            `json:"type"`
	Operation      OperationType          `json:"operation"` // subscribe or unsubscribe
	Schema         string                 `json:"schema,omitempty"`
	Entity         string                 `json:"entity"`
	Options        *common.RequestOptions `json:"options,omitempty"`         // Filters for subscription
	SubscriptionID string                 `json:"subscription_id,omitempty"` // For unsubscribe
}

// NewRequestMessage creates a new request message
func NewRequestMessage(id string, operation OperationType, schema, entity string) *RequestMessage {
	return &RequestMessage{
		ID:        id,
		Type:      MessageTypeRequest,
		Operation: operation,
		Schema:    schema,
		Entity:    entity,
	}
}

// NewResponseMessage creates a new response message
func NewResponseMessage(id string, success bool, data interface{}) *ResponseMessage {
	return &ResponseMessage{
		ID:        id,
		Type:      MessageTypeResponse,
		Success:   success,
		Data:      data,
		Timestamp: time.Now(),
	}
}

// NewErrorResponse creates an error response message
func NewErrorResponse(id string, code, message string) *ResponseMessage {
	return &ResponseMessage{
		ID:      id,
		Type:    MessageTypeResponse,
		Success: false,
		Error: &ErrorInfo{
			Code:    code,
			Message: message,
		},
		Timestamp: time.Now(),
	}
}

// NewNotificationMessage creates a new notification message
func NewNotificationMessage(subscriptionID string, operation OperationType, schema, entity string, data interface{}) *NotificationMessage {
	return &NotificationMessage{
		Type:           MessageTypeNotification,
		Operation:      operation,
		SubscriptionID: subscriptionID,
		Schema:         schema,
		Entity:         entity,
		Data:           data,
		Timestamp:      time.Now(),
	}
}

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

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

// ToJSON converts a response message to JSON bytes
func (r *ResponseMessage) ToJSON() ([]byte, error) {
	return json.Marshal(r)
}

// ToJSON converts a notification message to JSON bytes
func (n *NotificationMessage) ToJSON() ([]byte, error) {
	return json.Marshal(n)
}

// IsValid checks if a message is valid
func (m *Message) IsValid() bool {
	// Type must be set
	if m.Type == "" {
		return false
	}

	// Request messages must have an ID, operation, and entity
	if m.Type == MessageTypeRequest {
		return m.ID != "" && m.Operation != "" && m.Entity != ""
	}

	// Subscription messages must have an ID and operation
	if m.Type == MessageTypeSubscription {
		return m.ID != "" && m.Operation != ""
	}

	return true
}
