import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest'
import WebSocket from 'ws'
import { createInitialState } from '../../src/gameState.js'

// startServer() usa src/persist.js per caricare/salvare lo stato reale su disco
// (.segnapunti/state.json): lo mockiamo per non toccare lo stato di una partita
// vera durante i test, ed esercitare in isolamento l'avvio di HTTP + WebSocket.
const saveState = vi.fn()
vi.mock('../../src/persist.js', () => ({
    loadState: () => createInitialState(),
    saveState,
}))

const { startServer } = await import('../../server.js')

describe('startServer (server.js)', () => {
    let server
    let port

    beforeAll(async () => {
        const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
        server = startServer(0)
        await new Promise((resolve) => server.on('listening', resolve))
        port = server.address().port
        consoleSpy.mockRestore()
    })

    afterAll(async () => {
        await new Promise((resolve) => server.close(resolve))
    })

    it('stampa le info del server all\'avvio', async () => {
        const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
        const s = startServer(0)
        await new Promise((resolve) => s.on('listening', resolve))
        const allLogs = consoleSpy.mock.calls.map(c => c[0]).join('\n')
        expect(allLogs).toContain('Segnapunti Server')
        consoleSpy.mockRestore()
        await new Promise((resolve) => s.close(resolve))
    })

    it('accetta una connessione WebSocket su /ws', async () => {
        const ws = new WebSocket(`ws://127.0.0.1:${port}/ws`)
        await new Promise((resolve, reject) => {
            ws.on('open', resolve)
            ws.on('error', reject)
        })
        ws.close()
    })

    it('rifiuta l\'upgrade su un percorso diverso da /ws', async () => {
        const ws = new WebSocket(`ws://127.0.0.1:${port}/altro-percorso`)
        await new Promise((resolve) => {
            ws.on('error', () => resolve())
            ws.on('open', () => { ws.close(); resolve() })
        })
    })

    it('un\'azione dal controller invoca saveState (onStateChange)', async () => {
        saveState.mockClear()
        const ws = new WebSocket(`ws://127.0.0.1:${port}/ws`)
        await new Promise((resolve, reject) => {
            ws.on('open', resolve)
            ws.on('error', reject)
        })
        ws.send(JSON.stringify({ type: 'register', role: 'controller' }))
        await new Promise((resolve) => ws.once('message', resolve))

        ws.send(JSON.stringify({ type: 'action', action: { type: 'incPunt', team: 'home' } }))
        await new Promise((resolve) => ws.once('message', resolve))

        expect(saveState).toHaveBeenCalled()
        ws.close()
    })
})
