package com.doctate.watch.net

import com.doctate.watch.domain.parseOnelinersResponse
import com.doctate.watch.settings.Settings
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request

/**
 * Conditional-GET client for `/api/oneliners`. Wire format mirrors
 * `doctate-desktop::server_sync::poll_once`:
 *
 * - Always sends `X-API-Key`.
 * - If [poll] receives a non-null `etag`, sends `If-None-Match: <etag>`.
 * - 200 → parse body, surface new ETag (if any).
 * - 304 → no body.
 * - 408/429/5xx → [PollOutcome.TransientHttp] (worker backs off).
 * - Anything else (4xx) → also surfaced as TransientHttp; we don't want
 *   the polling loop to die over a one-off auth glitch — the upload
 *   path's terminal-vs-transient distinction is more nuanced.
 */
class OnelinersClient(
    private val http: OkHttpClient,
    private val settings: Settings,
) {
    suspend fun poll(etag: String?): PollOutcome = withContext(Dispatchers.IO) {
        val builder = Request.Builder()
            .url(settings.serverUrl.trimEnd('/') + ONELINERS_PATH)
            .header(API_KEY_HEADER, settings.apiKey)
            .get()
        if (etag != null) builder.header(IF_NONE_MATCH, etag)

        try {
            http.newCall(builder.build()).execute().use { response ->
                when (response.code) {
                    200 -> {
                        val body = response.body?.string().orEmpty()
                        val parsed = parseOnelinersResponse(body)
                        val newEtag = response.header(ETAG)
                        PollOutcome.Success(parsed, newEtag)
                    }
                    304 -> PollOutcome.NotModified
                    else -> PollOutcome.TransientHttp(response.code)
                }
            }
        } catch (e: Exception) {
            PollOutcome.Network(e)
        }
    }

    companion object {
        const val API_KEY_HEADER = "X-API-Key"
        const val ONELINERS_PATH = "/api/oneliners"
        const val IF_NONE_MATCH = "If-None-Match"
        const val ETAG = "ETag"
    }
}
