package com.example.myapplication.network

import okhttp3.*
import okio.Buffer
import org.json.JSONObject
import java.io.IOException
import java.util.concurrent.TimeUnit
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

object NetworkClient {

    // 你自己后端的 base url
    private const val BASE_URL = "http://192.168.2.21:7529/api"

    // 专门用于 SSE 的 OkHttpClient：readTimeout = 0 代表不超时，一直保持连接
    private val sseClient: OkHttpClient by lazy {
        OkHttpClient.Builder()
            .readTimeout(0, TimeUnit.MILLISECONDS)  // SSE 必须不能有读超时
            .build()
    }

    /**
     * 启动一次 SSE 流式请求
     * @param question 用户问题（你要传给后端的）
     * @return Call，可用于取消（比如用户关闭键盘时）
     */
    fun startLlmStream(
        question: String,
        callback: LlmStreamCallback
    ): Call {
        //  根据你后端的接口改：是 POST 还是 GET，参数格式是什么
        val json = JSONObject().apply {
            put("query", question)   // 假设你后端字段叫 query
        }

        val requestBody = json.toString()
            .toRequestBody("application/json; charset=utf-8".toMediaType())

        val request = Request.Builder()
            .url("$BASE_URL/llm/stream")   // TODO: 换成你真实的 SSE 路径
            .post(requestBody)
            // 有些 SSE 接口会要求 Accept
            .addHeader("Accept", "text/event-stream")
            .build()

        val call = sseClient.newCall(request)

        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                if (call.isCanceled()) return  // 被主动取消就不用回调错误了
                callback.onError(e)
            }

            override fun onResponse(call: Call, response: Response) {
                if (!response.isSuccessful) {
                    callback.onError(IOException("SSE failed: ${response.code}"))
                    response.close()
                    return
                }

                val body = response.body ?: run {
                    callback.onError(IOException("Empty body"))
                    return
                }

                // 长连接读取：一行一行读，直到服务器关闭或我们取消
                body.use { b ->
                    val source = b.source()
                    try {
                        while (!source.exhausted() && !call.isCanceled()) {
                            val line = source.readUtf8Line() ?: break
                            if (line.isBlank()) {
                                // SSE 中空行代表一个 event 结束，这里可以忽略
                                continue
                            }

                            // 兼容两种格式：
                            // 1) 标准 SSE: "data: { ... }"
                            // 2) 服务器直接一行一个 JSON: "{ ... }"
                            val payload = if (line.startsWith("data:")) {
                                line.substringAfter("data:").trim()
                            } else {
                                line.trim()
                            }

                            // 你日志里是：
                            // {"type":"llm_chunk","data":"Her"}
                            // {"type":"done","data":null}
                            try {
                                val jsonObj = JSONObject(payload)
                                val type = jsonObj.optString("type")
                                val data =
                                    if (jsonObj.has("data") && !jsonObj.isNull("data"))
                                        jsonObj.getString("data")
                                    else
                                        null

                                callback.onEvent(type, data)
                            } catch (e: Exception) {
                                // 解析失败就忽略这一行（或者你可以打印下日志）
                                // Log.e("NetworkClient", "Bad SSE line: $payload", e)
                            }
                        }
                    } catch (ioe: IOException) {
                        if (!call.isCanceled()) {
                            callback.onError(ioe)
                        }
                    }
                }
            }
        })

        return call
    }
}
