/**
 * Types for mizan/channels
 */

export type ConnectionStatus = 'connecting' | 'connected' | 'disconnected'

export interface ChannelSubscription<TParams = unknown, TServerMessage = unknown, TReactMessage = unknown> {
    /** Current connection status */
    status: ConnectionStatus

    /** Received messages */
    messages: TServerMessage[]

    /** Send a message (if channel accepts ReactMessage) */
    send: TReactMessage extends never ? never : (message: TReactMessage) => void

    /** Unsubscribe from the channel */
    unsubscribe: () => void

    /** Clear accumulated messages */
    clearMessages: () => void
}

export interface SubscribeOptions {
    /** Called when subscribed successfully */
    onSubscribed?: () => void

    /** Called when a message is received */
    onMessage?: (message: unknown) => void

    /** Called on error */
    onError?: (error: string) => void

    /** Called when unsubscribed */
    onUnsubscribed?: () => void
}

/**
 * Protocol messages sent over the WebSocket
 */
export interface SubscribeAction {
    action: 'subscribe'
    channel: string
    params: Record<string, unknown>
}

export interface UnsubscribeAction {
    action: 'unsubscribe'
    channel: string
    params: Record<string, unknown>
}

export interface MessageAction {
    action: 'message'
    channel: string
    params: Record<string, unknown>
    data: unknown
}

export type OutgoingMessage = SubscribeAction | UnsubscribeAction | MessageAction

export interface IncomingSubscribed {
    subscribed: true
    channel: string
    params: Record<string, unknown>
}

export interface IncomingUnsubscribed {
    unsubscribed: true
    channel: string
    params: Record<string, unknown>
}

export interface IncomingMessage {
    type: string
    data: unknown
}

export interface IncomingError {
    error: string
    channel?: string
}

export type IncomingPayload = IncomingSubscribed | IncomingUnsubscribed | IncomingMessage | IncomingError
