package xyz.cottongin.radio247.audio

import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Test

class StreamConnectionTest {

    private val server = MockWebServer()

    @After
    fun tearDown() {
        server.shutdown()
    }

    @Test
    fun sends_icy_metadata_header_and_reads_metaint_from_response() {
        server.enqueue(
            MockResponse()
                .setHeader("icy-metaint", "16000")
                .setHeader("Content-Type", "audio/mpeg")
                .setBody("fake audio data")
        )
        server.start()

        val conn = StreamConnection(server.url("/stream").toString())
        conn.open()

        val request = server.takeRequest()
        assertEquals("1", request.getHeader("Icy-MetaData"))
        assertEquals(16000, conn.metaint)
        assertNotNull(conn.inputStream)

        conn.close()
    }

    @Test
    fun metaint_is_null_when_server_does_not_provide_it() {
        server.enqueue(
            MockResponse()
                .setHeader("Content-Type", "audio/mpeg")
                .setBody("fake audio data")
        )
        server.start()

        val conn = StreamConnection(server.url("/stream").toString())
        conn.open()

        assertNull(conn.metaint)
        assertNotNull(conn.inputStream)

        conn.close()
    }

    @Test(expected = ConnectionFailed::class)
    fun throws_ConnectionFailed_on_HTTP_error() {
        server.enqueue(MockResponse().setResponseCode(404))
        server.start()

        val conn = StreamConnection(server.url("/stream").toString())
        conn.open()
    }

    @Test
    fun throws_ConnectionFailed_on_network_error() {
        server.start()
        val url = server.url("/stream").toString()
        server.shutdown()

        try {
            val conn = StreamConnection(url)
            conn.open()
            fail("Expected ConnectionFailed")
        } catch (e: ConnectionFailed) {
            assertTrue(e.message!!.contains("Network error"))
            assertNotNull(e.cause)
        }
    }

    @Test
    fun close_cleans_up_resources() {
        server.enqueue(
            MockResponse()
                .setHeader("icy-metaint", "16000")
                .setBody("fake audio data")
        )
        server.start()

        val conn = StreamConnection(server.url("/stream").toString())
        conn.open()
        assertNotNull(conn.inputStream)
        assertNotNull(conn.metaint)

        conn.close()

        assertNull(conn.inputStream)
        assertNull(conn.metaint)
    }

    @Test
    fun sends_user_agent_header() {
        server.enqueue(
            MockResponse()
                .setHeader("icy-metaint", "16000")
                .setBody("fake audio data")
        )
        server.start()

        val conn = StreamConnection(server.url("/stream").toString())
        conn.open()

        val request = server.takeRequest()
        assertEquals("Radio247/1.0", request.getHeader("User-Agent"))

        conn.close()
    }
}
