import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import { mkdtempSync, writeFileSync, rmSync } from 'fs'
import { tmpdir } from 'os'
import { join } from 'path'
import { createApp } from '../../server.js'

// Usiamo una dist e una cartella spot temporanee con file marcatori, così il
// test non dipende da una build reale ed è deterministico.
let server
let baseUrl
let distDir
let spotDir

beforeAll(async () => {
    distDir = mkdtempSync(join(tmpdir(), 'segnapunti-dist-'))
    writeFileSync(join(distDir, 'index.html'), 'DISPLAY_MARKER')
    writeFileSync(join(distDir, 'controller.html'), 'CONTROLLER_MARKER')
    writeFileSync(join(distDir, 'app.js'), 'ASSET_MARKER')

    spotDir = mkdtempSync(join(tmpdir(), 'segnapunti-spot-'))
    writeFileSync(join(spotDir, 'b.mp4'), 'VIDEO_B')
    writeFileSync(join(spotDir, 'a.mp4'), 'VIDEO_A')
    writeFileSync(join(spotDir, 'note.txt'), 'NON_VIDEO')

    const app = createApp(distDir, spotDir)
    await new Promise((resolve) => {
        server = app.listen(0, () => {
            baseUrl = `http://127.0.0.1:${server.address().port}`
            resolve()
        })
    })
})

afterAll(async () => {
    await new Promise((resolve) => server.close(resolve))
    rmSync(distDir, { recursive: true, force: true })
    rmSync(spotDir, { recursive: true, force: true })
})

async function get(path) {
    const res = await fetch(baseUrl + path)
    return { status: res.status, body: await res.text() }
}

describe('Routing server (server.js)', () => {
    it('GET / serve la pagina display', async () => {
        const { status, body } = await get('/')
        expect(status).toBe(200)
        expect(body).toBe('DISPLAY_MARKER')
    })

    it('GET /display serve la pagina display', async () => {
        expect((await get('/display')).body).toBe('DISPLAY_MARKER')
    })

    it('GET /display/qualsiasi serve comunque la pagina display (SPA)', async () => {
        expect((await get('/display/foo/bar')).body).toBe('DISPLAY_MARKER')
    })

    it('GET /controller serve la pagina controller', async () => {
        expect((await get('/controller')).body).toBe('CONTROLLER_MARKER')
    })

    it('GET /controller/qualsiasi serve comunque la pagina controller', async () => {
        expect((await get('/controller/foo')).body).toBe('CONTROLLER_MARKER')
    })

    it('serve gli asset statici dalla dist', async () => {
        const { status, body } = await get('/app.js')
        expect(status).toBe(200)
        expect(body).toBe('ASSET_MARKER')
    })

    it('GET /spot/list elenca i soli .mp4 in ordine alfabetico', async () => {
        const res = await fetch(baseUrl + '/spot/list')
        expect(res.status).toBe(200)
        expect(await res.json()).toEqual(['a.mp4', 'b.mp4'])
    })

    it('serve i video staticamente da /spot/<file>', async () => {
        const { status, body } = await get('/spot/a.mp4')
        expect(status).toBe(200)
        expect(body).toBe('VIDEO_A')
    })

    it('GET /spot/list ritorna [] se la cartella spot non esiste', async () => {
        const app = createApp(distDir, join(spotDir, 'inesistente'))
        const srv = await new Promise((resolve) => {
            const s = app.listen(0, () => resolve(s))
        })
        try {
            const res = await fetch(`http://127.0.0.1:${srv.address().port}/spot/list`)
            expect(res.status).toBe(200)
            expect(await res.json()).toEqual([])
        } finally {
            await new Promise((resolve) => srv.close(resolve))
        }
    })
})
