package com.bytelyst.platform

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.net.URLEncoder

/**
 * Feature flag client for platform-service.
 *
 * Polls GET /api/flags/poll on a configurable interval and caches results
 * in memory. Consumers call [isEnabled] with a flag key.
 *
 * Mirrors the Swift BLFeatureFlagClient API.
 */
class BLFeatureFlagClient(
    private val config: BLPlatformConfig,
    private val pollIntervalMs: Long = 5 * 60 * 1000L,
) {
    @Serializable
    private data class FlagResponse(val flags: Map<String, Boolean> = emptyMap())

    private val json = Json { ignoreUnknownKeys = true }
    private val client = BLPlatformClient(config)
    private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    private var pollJob: Job? = null

    @Volatile
    private var flags: Map<String, Boolean> = emptyMap()

    private var userId: String? = null

    // ── Public API ───────────────────────────────────────────

    /**
     * Initialize and start polling. Call once at app startup.
     */
    fun init(userId: String? = null) {
        this.userId = userId
        scope.launch { fetchFlags() }
        startPolling()
    }

    fun isEnabled(key: String): Boolean = flags[key] == true

    fun getAllFlags(): Map<String, Boolean> = flags.toMap()

    /**
     * Force a refresh of feature flags.
     */
    suspend fun refresh() {
        fetchFlags()
    }

    fun stop() {
        pollJob?.cancel()
        pollJob = null
    }

    // ── Private ──────────────────────────────────────────────

    private fun startPolling() {
        if (pollJob != null) return
        pollJob = scope.launch {
            while (isActive) {
                delay(pollIntervalMs)
                fetchFlags()
            }
        }
    }

    private suspend fun fetchFlags() {
        try {
            val enc = { v: String -> URLEncoder.encode(v, "UTF-8") }
            val qs = buildString {
                append("?platform=${enc(config.platform)}")
                userId?.let { append("&userId=${enc(it)}") }
            }
            val response = client.request("GET", "/api/flags/poll$qs", skipAuth = true)
            val result = json.decodeFromString<FlagResponse>(response)
            flags = result.flags
        } catch (_: Exception) {
            // Keep existing flags on failure
        }
    }
}
