package com.doctate.watch.net

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
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
import org.junit.runner.RunWith
import java.io.File

@RunWith(AndroidJUnit4::class)
class UploadClientTest {
    private lateinit var server: MockWebServer
    private lateinit var client: UploadClient
    private lateinit var audioFile: File

    @Before fun setUp() {
        server = MockWebServer().apply { start() }
        val settings = object : Settings {
            override val serverUrl = server.url("/").toString().trimEnd('/')
            override val apiKey = "key-dr_test"
        }
        client = UploadClient(OkHttpClient(), settings)
        audioFile = copyAssetToTempFile("sample.m4a")
    }

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

    @Test fun upload_sends_correct_multipart_and_returns_success_on_200() = runTest {
        server.enqueue(
            MockResponse().setResponseCode(200).setBody(
                """{"case_id":"550e8400-e29b-41d4-a716-446655440000","recorded_at":"2026-04-23T10:30:00Z","status":"received"}"""
            )
        )

        val result = client.upload(
            caseId = "550e8400-e29b-41d4-a716-446655440000",
            recordedAt = "2026-04-23T10:30:00Z",
            audio = audioFile,
        )

        val req = server.takeRequest()
        assertThat(req.method).isEqualTo("POST")
        assertThat(req.path).isEqualTo("/api/upload")
        assertThat(req.getHeader("X-API-Key")).isEqualTo("key-dr_test")
        val body = req.body.readUtf8()
        assertThat(body).contains("name=\"case_id\"")
        assertThat(body).contains("550e8400-e29b-41d4-a716-446655440000")
        assertThat(body).contains("name=\"recorded_at\"")
        assertThat(body).contains("2026-04-23T10:30:00Z")
        assertThat(body).contains("name=\"audio\"")
        assertThat(body).contains("Content-Type: audio/mp4")
        assertThat(result).isInstanceOf(UploadResult.Success::class.java)
    }

    @Test fun upload_classifies_5xx_as_transient() = runTest {
        server.enqueue(MockResponse().setResponseCode(500).setBody("oh no"))
        val result = client.upload("uuid", "2026-04-23T10:30:00Z", audioFile)
        assertThat(result).isInstanceOf(UploadResult.Transient::class.java)
    }

    @Test fun upload_classifies_401_as_terminal() = runTest {
        server.enqueue(MockResponse().setResponseCode(401).setBody("nope"))
        val result = client.upload("uuid", "2026-04-23T10:30:00Z", audioFile)
        assertThat(result).isInstanceOf(UploadResult.Terminal::class.java)
    }

    @Test fun upload_classifies_io_error_as_transient() = runTest {
        server.shutdown()
        val result = client.upload("uuid", "2026-04-23T10:30:00Z", audioFile)
        assertThat(result).isInstanceOf(UploadResult.Transient::class.java)
    }

    private fun copyAssetToTempFile(assetName: String): File {
        val instrumentation = InstrumentationRegistry.getInstrumentation()
        // Assets are packaged with the test APK; cache dir lives under the app APK.
        val testCtx = instrumentation.context
        val appCtx = instrumentation.targetContext
        val tmp = File.createTempFile("upload-test-", ".m4a", appCtx.cacheDir)
        testCtx.assets.open(assetName).use { input ->
            tmp.outputStream().use { output -> input.copyTo(output) }
        }
        return tmp
    }
}
