package com.doctate.watch.net

import com.doctate.watch.settings.Settings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import okhttp3.OkHttpClient
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
import org.junit.Test

class OnelinersClientTest {
    private lateinit var server: MockWebServer
    private lateinit var client: OnelinersClient

    @Before fun setUp() {
        server = MockWebServer()
        server.start()
        val settings = object : Settings {
            override val serverUrl = server.url("/").toString().trimEnd('/')
            override val apiKey = "test-key"
        }
        client = OnelinersClient(OkHttpClient(), settings)
    }

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

    @Test fun success_returns_parsed_body_and_etag() = runTest {
        val body = """
            {
              "as_of":"2026-04-26T12:00:00Z",
              "window_hours":72,
              "oneliners":[]
            }
        """.trimIndent()
        server.enqueue(
            MockResponse()
                .setResponseCode(200)
                .setHeader("ETag", "W/\"abc-72\"")
                .setBody(body),
        )

        val outcome = client.poll(etag = null)
        assertThat(outcome).isInstanceOf(PollOutcome.Success::class.java)
        val success = outcome as PollOutcome.Success
        assertThat(success.etag).isEqualTo("W/\"abc-72\"")
        assertThat(success.response.windowHours).isEqualTo(72)
    }

    @Test fun not_modified_returns_NotModified() = runTest {
        server.enqueue(MockResponse().setResponseCode(304).setHeader("ETag", "W/\"abc-72\""))
        val outcome = client.poll(etag = "W/\"abc-72\"")
        assertThat(outcome).isEqualTo(PollOutcome.NotModified)
    }

    @Test fun if_none_match_header_is_sent_when_etag_provided() = runTest {
        server.enqueue(MockResponse().setResponseCode(304))
        client.poll(etag = "W/\"prev-tag\"")
        val request = server.takeRequest()
        assertThat(request.getHeader("If-None-Match")).isEqualTo("W/\"prev-tag\"")
        assertThat(request.getHeader("X-API-Key")).isEqualTo("test-key")
    }

    @Test fun no_if_none_match_when_etag_null() = runTest {
        server.enqueue(MockResponse().setResponseCode(200).setBody(emptyResponseBody()))
        client.poll(etag = null)
        val request = server.takeRequest()
        assertThat(request.getHeader("If-None-Match")).isNull()
    }

    @Test fun http_503_classifies_as_TransientHttp() = runTest {
        server.enqueue(MockResponse().setResponseCode(503))
        val outcome = client.poll(etag = null)
        assertThat(outcome).isEqualTo(PollOutcome.TransientHttp(503))
    }

    @Test fun network_failure_yields_Network_outcome() = runTest {
        server.shutdown() // server is down → connection refused
        val outcome = client.poll(etag = null)
        assertThat(outcome).isInstanceOf(PollOutcome.Network::class.java)
    }

    private fun emptyResponseBody() = """
        {"as_of":"2026-04-26T12:00:00Z","window_hours":72,"oneliners":[]}
    """.trimIndent()
}
