/**
 * Integration tests for channel hooks
 *
 * These tests call the REAL backend - no mocks.
 * Backend must be running: docker-compose up
 *
 * Run with: RUN_INTEGRATION_TESTS=true npm run test
 */

import { renderHook, waitFor } from '@testing-library/react'
import { ReactNode } from 'react'
import { ChannelProvider } from '../context'
import { useChannel, useChannelLatest, useRPC } from '../hooks'
import { ChannelConnection } from '../connection'
import { describeIntegration, WS_URL } from '../../testing'

describeIntegration('useChannel (integration)', () => {
    let connection: ChannelConnection

    beforeEach(() => {
        connection = new ChannelConnection({
            url: WS_URL,
            reconnect: false,
        })
    })

    afterEach(() => {
        connection.disconnect()
    })

    const createWrapper = () => {
        return function Wrapper({ children }: { children: ReactNode }) {
            return (
                <ChannelProvider connection={connection} autoConnect={true}>
                    {children}
                </ChannelProvider>
            )
        }
    }

    describe('subscription', () => {
        it('should subscribe to channel when connection is ready', async () => {
            const { result } = renderHook(
                () => useChannel<{ room: string }, { text: string }, { text: string }>('chat', { room: 'test' }),
                { wrapper: createWrapper() }
            )

            // Wait for connection to establish
            await waitFor(() => {
                // Status should progress from connecting
                expect(['connecting', 'connected', 'subscribed']).toContain(result.current.status)
            }, { timeout: 5000 })

            // Should have expected API
            expect(typeof result.current.send).toBe('function')
            expect(typeof result.current.clearMessages).toBe('function')
            expect(typeof result.current.unsubscribe).toBe('function')
            expect(Array.isArray(result.current.messages)).toBe(true)
        })

    })
})

describeIntegration('useChannelLatest (integration)', () => {
    let connection: ChannelConnection

    beforeEach(() => {
        connection = new ChannelConnection({
            url: WS_URL,
            reconnect: false,
        })
    })

    afterEach(() => {
        connection.disconnect()
    })

    const createWrapper = () => {
        return function Wrapper({ children }: { children: ReactNode }) {
            return (
                <ChannelProvider connection={connection} autoConnect={true}>
                    {children}
                </ChannelProvider>
            )
        }
    }

})

describeIntegration('useRPC (integration)', () => {
    let connection: ChannelConnection

    beforeEach(() => {
        connection = new ChannelConnection({
            url: WS_URL,
            reconnect: false,
        })
    })

    afterEach(() => {
        connection.disconnect()
    })

    const createWrapper = () => {
        return function Wrapper({ children }: { children: ReactNode }) {
            return (
                <ChannelProvider connection={connection} autoConnect={true}>
                    {children}
                </ChannelProvider>
            )
        }
    }

    it('should track connection status', async () => {
        const { result } = renderHook(() => useRPC(), { wrapper: createWrapper() })

        // Wait for connection
        await waitFor(() => {
            expect(result.current.status).toBe('connected')
        }, { timeout: 5000 })
    })

    it('should call backend echo function via RPC', async () => {
        const { result } = renderHook(() => useRPC(), { wrapper: createWrapper() })

        // Wait for connection
        await waitFor(() => {
            expect(result.current.status).toBe('connected')
        }, { timeout: 5000 })

        // Call echo function
        const response = await result.current.call<{ text: string }, { message: string }>(
            'echo',
            { text: 'rpc test' }
        )

        expect(response).toHaveProperty('message')
        expect(response.message).toContain('rpc test')
    })

    it('should call backend add function via RPC', async () => {
        const { result } = renderHook(() => useRPC(), { wrapper: createWrapper() })

        // Wait for connection
        await waitFor(() => {
            expect(result.current.status).toBe('connected')
        }, { timeout: 5000 })

        // Call add function
        const response = await result.current.call<{ a: number; b: number }, { result: number }>(
            'add',
            { a: 7, b: 8 }
        )

        expect(response).toHaveProperty('result', 15)
    })
})

