'use client'

/**
 * React context for mizan/channels
 */

import { createContext, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
import { ChannelConnection, type ChannelConnectionOptions } from './connection'
import type { ConnectionStatus } from './types'

interface ChannelContextValue {
    connection: ChannelConnection
    status: ConnectionStatus
}

const ChannelContext = createContext<ChannelContextValue | null>(null)

export interface ChannelProviderProps {
    children: ReactNode

    /** WebSocket URL (default: /ws/) */
    url?: string

    /** Reconnect on disconnect (default: true) */
    reconnect?: boolean

    /** Reconnection delay in ms (default: 1000) */
    reconnectDelay?: number

    /** Maximum reconnection attempts (default: 10) */
    maxReconnectAttempts?: number

    /** Connect automatically on mount (default: true) */
    autoConnect?: boolean

    /** Custom connection instance (for testing) */
    connection?: ChannelConnection
}

export function ChannelProvider({
    children,
    url,
    reconnect,
    reconnectDelay,
    maxReconnectAttempts,
    autoConnect = true,
    connection: providedConnection,
}: ChannelProviderProps) {
    const connectionRef = useRef<ChannelConnection | null>(null)

    // Use provided connection or create one
    if (!connectionRef.current) {
        connectionRef.current = providedConnection ?? new ChannelConnection({
            url,
            reconnect,
            reconnectDelay,
            maxReconnectAttempts,
        })
    }

    const connection = connectionRef.current

    // Track status for context value
    const [status, setStatus] = useState<ConnectionStatus>(connection.status)

    useEffect(() => {
        const unsubscribe = connection.onStatusChange(setStatus)

        if (autoConnect) {
            connection.connect()
        }

        return () => {
            unsubscribe()
            connection.disconnect()
        }
    }, [connection, autoConnect])

    const value = useMemo(() => ({
        connection,
        status,
    }), [connection, status])

    return (
        <ChannelContext value={value}>
            {children}
        </ChannelContext>
    )
}

export function useChannelContext(): ChannelContextValue {
    const context = useContext(ChannelContext)
    if (!context) {
        throw new Error('useChannelContext must be used within a ChannelProvider')
    }
    return context
}

export function useChannelStatus(): ConnectionStatus {
    const { status } = useChannelContext()
    return status
}
