package com.doctate.watch.net

import android.util.Log
import com.doctate.watch.domain.OnelinerState
import com.doctate.watch.domain.onelinerFromJson
import com.doctate.watch.settings.Settings
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject

/**
 * `PUT /api/cases/{case_id}/oneliner` — push a doctor's manual override
 * to the server. Mirrors `OnelinerOverrideRequest` from
 * `common/src/oneliners.rs` (just `{text: string}`); the server
 * timestamps it server-side as `OnelinerState.Manual` and persists
 * `oneliner.json` next to the audio.
 *
 * The watch fires this fire-and-forget right after a tap-to-edit save:
 * UI updates optimistically via `caseStore.setOnelinerLocal`, then we
 * push to the server. On failure we log — the next successful poll
 * usually pulls in the server-side state and reconciles. Pre-upload
 * edits (case_dir doesn't exist server-side) get a 404 here; the local
 * Manual sticks until the case is uploaded and the user re-edits.
 */
class OnelinerOverrideClient(
    private val http: OkHttpClient,
    private val settings: Settings,
) {
    sealed interface Outcome {
        data class Success(val state: OnelinerState) : Outcome
        data class HttpError(val code: Int, val body: String) : Outcome
        data class Network(val cause: Throwable) : Outcome
    }

    suspend fun put(caseId: String, text: String): Outcome = withContext(Dispatchers.IO) {
        val payload = JSONObject().put("text", text).toString()
        val request = Request.Builder()
            .url(settings.serverUrl.trimEnd('/') + buildPath(caseId))
            .header(API_KEY_HEADER, settings.apiKey)
            .put(payload.toRequestBody(JSON.toMediaType()))
            .build()
        try {
            http.newCall(request).execute().use { response ->
                val body = response.body?.string().orEmpty()
                if (response.code in 200..299) {
                    Outcome.Success(onelinerFromJson(JSONObject(body)))
                } else {
                    Log.w(TAG, "PUT oneliner caseId=${caseId.take(8)} http=${response.code} body=$body")
                    Outcome.HttpError(response.code, body)
                }
            }
        } catch (e: Exception) {
            Log.w(TAG, "PUT oneliner caseId=${caseId.take(8)} network: ${e.message}")
            Outcome.Network(e)
        }
    }

    companion object {
        private const val TAG = "OnelinerOverride"
        private const val API_KEY_HEADER = "X-API-Key"
        private const val JSON = "application/json"
        private fun buildPath(caseId: String): String = "/api/cases/$caseId/oneliner"
    }
}
