package com.jishisongfu.duobibi.ui.mine

import android.app.Application
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.jishisongfu.duobibi.BuildConfig
import com.jishisongfu.duobibi.data.api.ArenaApi
import com.jishisongfu.duobibi.data.api.ArenaQuoteRequest
import com.jishisongfu.duobibi.service.FloatingWindowService
import com.jishisongfu.duobibi.util.PermissionUtil
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.net.HttpURLConnection
import java.net.URL
import javax.inject.Inject

enum class DiagStatus { PENDING, RUNNING, OK, FAIL, UNKNOWN }

data class DiagItem(
    val key: String,
    val label: String,
    val status: DiagStatus = DiagStatus.PENDING,
    val detail: String? = null,
    val latencyMs: Long? = null,
)

@HiltViewModel
class DiagnosticsViewModel @Inject constructor(
    app: Application,
    private val arenaApi: ArenaApi,
) : AndroidViewModel(app) {

    private val _items = MutableStateFlow(
        listOf(
            DiagItem("accessibility", "无障碍服务"),
            DiagItem("overlay", "悬浮窗权限"),
            DiagItem("floating", "比价浮窗服务"),
            DiagItem("network", "网络连接"),
            DiagItem("backend", "后端连通"),
            DiagItem("llm", "比价识别(LLM)"),
        )
    )
    val items: StateFlow<List<DiagItem>> = _items.asStateFlow()

    private val _running = MutableStateFlow(false)
    val running: StateFlow<Boolean> = _running.asStateFlow()

    fun runAll() {
        if (_running.value) return
        viewModelScope.launch {
            _running.value = true
            set("accessibility", if (PermissionUtil.accessibilityGranted(getApplication())) DiagStatus.OK else DiagStatus.FAIL)
            set("overlay", if (PermissionUtil.overlayGranted(getApplication())) DiagStatus.OK else DiagStatus.FAIL)
            set("floating", if (FloatingWindowService.isRunning()) DiagStatus.OK else DiagStatus.FAIL,
                if (FloatingWindowService.isRunning()) "运行中" else "未启动,先打开 App 并授权")
            set("network", if (online()) DiagStatus.OK else DiagStatus.FAIL, if (online()) null else "未检测到可用网络")
            set("backend", DiagStatus.RUNNING)
            val (bs, bd, bl) = checkBackend()
            set("backend", bs, bd, bl)
            set("llm", DiagStatus.RUNNING)
            val (ls, ld, ll) = checkLlm()
            set("llm", ls, ld, ll)
            _running.value = false
        }
    }

    private fun set(key: String, status: DiagStatus, detail: String? = null, latency: Long? = null) {
        _items.value = _items.value.map { if (it.key == key) it.copy(status = status, detail = detail, latencyMs = latency) else it }
    }

    private fun online(): Boolean {
        val cm = getApplication<Application>().getSystemService(ConnectivityManager::class.java) ?: return false
        val caps = cm.activeNetwork?.let { cm.getNetworkCapabilities(it) } ?: return false
        return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
            caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
    }

    private suspend fun checkBackend(): Triple<DiagStatus, String?, Long?> = withContext(Dispatchers.IO) {
        val start = System.currentTimeMillis()
        try {
            val conn = (URL("${BuildConfig.BASE_URL}health").openConnection() as HttpURLConnection).apply {
                connectTimeout = 5000; readTimeout = 5000; requestMethod = "GET"
            }
            val code = conn.responseCode
            val latency = System.currentTimeMillis() - start
            conn.disconnect()
            if (code == 200) Triple(DiagStatus.OK, null, latency) else Triple(DiagStatus.FAIL, "HTTP $code", latency)
        } catch (e: Throwable) {
            Triple(DiagStatus.FAIL, e.message, null)
        }
    }

    private suspend fun checkLlm(): Triple<DiagStatus, String?, Long?> = withContext(Dispatchers.IO) {
        val start = System.currentTimeMillis()
        try {
            val resp = arenaApi.arenaQuote(ArenaQuoteRequest(title = "iPhone 15 Pro 256GB"))
            Triple(DiagStatus.OK, "常见价 ¥${resp.typicalPrice}", System.currentTimeMillis() - start)
        } catch (e: Throwable) {
            Triple(DiagStatus.FAIL, e.message, null)
        }
    }
}
