package com.doctate.watch.net

import com.doctate.watch.domain.OnelinerState
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 OnelinerOverrideClientTest {
    private lateinit var server: MockWebServer
    private lateinit var client: OnelinerOverrideClient

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

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

    @Test fun success_parses_returned_manual_state() = runTest {
        server.enqueue(
            MockResponse().setResponseCode(200).setBody(
                """{"kind":"manual","text":"Doctor wrote this","set_at":"2026-04-26T22:00:00Z"}""",
            ),
        )

        val outcome = client.put("case-aaa", "Doctor wrote this")
        assertThat(outcome).isInstanceOf(OnelinerOverrideClient.Outcome.Success::class.java)
        val state = (outcome as OnelinerOverrideClient.Outcome.Success).state
        assertThat(state).isInstanceOf(OnelinerState.Manual::class.java)
        assertThat((state as OnelinerState.Manual).text).isEqualTo("Doctor wrote this")
    }

    @Test fun sends_PUT_with_correct_path_headers_and_body() = runTest {
        server.enqueue(MockResponse().setResponseCode(200).setBody(stubManual()))
        client.put("550e8400-e29b-41d4-a716-446655440000", "neue Bezeichnung")

        val request = server.takeRequest()
        assertThat(request.method).isEqualTo("PUT")
        assertThat(request.path).isEqualTo("/api/cases/550e8400-e29b-41d4-a716-446655440000/oneliner")
        assertThat(request.getHeader("X-API-Key")).isEqualTo("test-key")
        assertThat(request.getHeader("Content-Type")).contains("application/json")
        assertThat(request.body.readUtf8()).contains("\"text\":\"neue Bezeichnung\"")
    }

    @Test fun http_404_classifies_as_HttpError_not_thrown() = runTest {
        server.enqueue(MockResponse().setResponseCode(404).setBody("not found"))
        val outcome = client.put("case-x", "anything")
        assertThat(outcome).isInstanceOf(OnelinerOverrideClient.Outcome.HttpError::class.java)
        assertThat((outcome as OnelinerOverrideClient.Outcome.HttpError).code).isEqualTo(404)
    }

    @Test fun http_400_validation_error_classifies_as_HttpError() = runTest {
        server.enqueue(MockResponse().setResponseCode(400).setBody("oneliner text must not be empty"))
        val outcome = client.put("case-x", "")
        assertThat(outcome).isInstanceOf(OnelinerOverrideClient.Outcome.HttpError::class.java)
        assertThat((outcome as OnelinerOverrideClient.Outcome.HttpError).code).isEqualTo(400)
    }

    @Test fun network_failure_yields_Network_outcome() = runTest {
        server.shutdown()
        val outcome = client.put("case-x", "text")
        assertThat(outcome).isInstanceOf(OnelinerOverrideClient.Outcome.Network::class.java)
    }

    private fun stubManual() = """{"kind":"manual","text":"x","set_at":"2026-04-26T22:00:00Z"}"""
}
