package ru.forbion.f7cloud.feature.files

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import okhttp3.Request
import ru.forbion.f7cloud.core.auth.AuthSession
import ru.forbion.f7cloud.core.network.NetworkFactory

/**
 * Прогрев Collabora / Richdocuments: кэш public WOPI URL и «холодный» TCP/HTTP к серверу офиса.
 * Сам документ каждый раз открывается по новой direct-ссылке (одноразовый токен F7cloud).
 */
object OfficeWarmup {
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    private val mutex = Mutex()

    @Volatile
    private var cachedServerUrl: String? = null

    @Volatile
    private var cachedCollaboraUrl: String? = null

    @Volatile
    private var lastWarmupAtMs: Long = 0L

    private const val WARMUP_INTERVAL_MS = 10 * 60 * 1000L

    fun getCachedCollaboraUrl(serverUrl: String): String {
        if (cachedServerUrl == serverUrl.trimEnd('/')) {
            return cachedCollaboraUrl.orEmpty()
        }
        return ""
    }

    /**
     * Вызывать при входе в «Файлы» или после логина — не блокирует UI.
     */
    fun warm(session: AuthSession, repository: RichdocumentsRepository = RichdocumentsRepository()) {
        val serverKey = session.serverUrl.trimEnd('/')
        val now = System.currentTimeMillis()
        if (cachedServerUrl == serverKey &&
            cachedCollaboraUrl?.isNotBlank() == true &&
            now - lastWarmupAtMs < WARMUP_INTERVAL_MS
        ) {
            return
        }
        scope.launch {
            mutex.withLock {
                runCatching {
                    val collabora = repository.fetchCollaboraPublicUrl(session).trim().trimEnd('/')
                    if (collabora.isNotBlank()) {
                        cachedServerUrl = serverKey
                        cachedCollaboraUrl = collabora
                        lastWarmupAtMs = System.currentTimeMillis()
                        pingCollabora(session, collabora)
                    }
                }
            }
        }
    }

    fun clear() {
        cachedServerUrl = null
        cachedCollaboraUrl = null
        lastWarmupAtMs = 0L
    }

    private fun pingCollabora(session: AuthSession, collaboraBase: String) {
        val client = NetworkFactory.newAuthedClientForOffice(
            session.username,
            session.appPassword,
            session.trustAllCerts,
        )
        val discoveryUrl = "$collaboraBase/hosting/discovery"
        runCatching {
            client.newCall(
                Request.Builder()
                    .url(discoveryUrl)
                    .header("User-Agent", OFFICE_WARMUP_UA)
                    .get()
                    .build(),
            ).execute().use { /* прогрев соединения */ }
        }
    }

    private const val OFFICE_WARMUP_UA =
        "F7cloud-Mobile/1.0 (OfficeWarmup)"
}
