package com.a2i.forwarder.store

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import com.a2i.forwarder.model.BarkServer
import com.a2i.forwarder.model.OFFICIAL_BARK_SERVER
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

private val Context.settingsDataStore: DataStore<Preferences> by preferencesDataStore(name = "a2i_settings")

class SettingsStore(
    private val context: Context,
    scope: CoroutineScope,
) {
    private val ds get() = context.settingsDataStore
    private val json = Json { ignoreUnknownKeys = true; encodeDefaults = true }

    private object K {
        val SERVERS = stringPreferencesKey("servers")
        val CURRENT = stringPreferencesKey("current")
        val ICON_PREFIX = stringPreferencesKey("icon_prefix")
        val FWD = booleanPreferencesKey("forwarding")
        val CODE = booleanPreferencesKey("code")
        val AD = booleanPreferencesKey("ad_filter")
        val SPECIAL = booleanPreferencesKey("special")
        val SKIP_ONGOING = booleanPreferencesKey("skip_ongoing")
        val AD_KW = stringPreferencesKey("ad_keywords")
    }

    private val defaultServers = listOf(
        BarkServer(id = ID_OFFICIAL, name = "Bark 官方", server = OFFICIAL_BARK_SERVER, deviceKey = "")
    )

    private val _servers = MutableStateFlow(defaultServers)
    val servers = _servers.asStateFlow()

    private val _currentServerId = MutableStateFlow(ID_OFFICIAL)
    val currentServer = MutableStateFlow<BarkServer?>(defaultServers.first())

    val iconPrefix = MutableStateFlow("")
    val forwardingEnabled = MutableStateFlow(true)
    val codeEnabled = MutableStateFlow(true)
    val adFilterEnabled = MutableStateFlow(true)
    val specialEnabled = MutableStateFlow(true)
    val skipOngoing = MutableStateFlow(true)
    val adKeywords = MutableStateFlow<List<String>>(emptyList()) // 用户自定义关键词

    init {
        scope.launch {
            ds.data.collect { p ->
                val list: List<BarkServer> = p[K.SERVERS]
                    ?.let { runCatching { json.decodeFromString<List<BarkServer>>(it) }.getOrNull() }
                    ?: defaultServers
                _servers.value = list
                _currentServerId.value = p[K.CURRENT] ?: ID_OFFICIAL
                currentServer.value = list.firstOrNull { it.id == _currentServerId.value } ?: list.firstOrNull()
                iconPrefix.value = p[K.ICON_PREFIX] ?: ""
                forwardingEnabled.value = p[K.FWD] ?: true
                codeEnabled.value = p[K.CODE] ?: true
                adFilterEnabled.value = p[K.AD] ?: true
                specialEnabled.value = p[K.SPECIAL] ?: true
                skipOngoing.value = p[K.SKIP_ONGOING] ?: true
                adKeywords.value = p[K.AD_KW]
                    ?.let { runCatching { json.decodeFromString<List<String>>(it) }.getOrNull() }
                    ?: emptyList()
            }
        }
    }

    private suspend fun edit(block: (androidx.datastore.preferences.core.MutablePreferences) -> Unit) =
        ds.edit(block)

    private suspend fun saveServers(list: List<BarkServer>) {
        edit { it[K.SERVERS] = json.encodeToString(list) }
        _servers.value = list
        refreshCurrent()
    }

    suspend fun addServer(name: String, server: String, key: String): BarkServer {
        val s = BarkServer(name = name.trim(), server = server.trim().removeSuffix("/"), deviceKey = key.trim())
        saveServers(_servers.value + s)
        if (_servers.value.count { it.id == s.id } == 1 && currentServer.value?.deviceKey.isNullOrBlank()) {
            setCurrent(s.id)
        }
        return s
    }

    suspend fun updateServer(s: BarkServer) = saveServers(_servers.value.map { if (it.id == s.id) s.copy(server = s.server.trim().removeSuffix("/")) else it })

    suspend fun deleteServer(id: String) {
        val list = _servers.value.filterNot { it.id == id }
        saveServers(list)
        if (_currentServerId.value == id) {
            setCurrent(if (list.isEmpty()) "" else list.first().id)
        }
    }

    suspend fun setCurrent(id: String) {
        edit { it[K.CURRENT] = id }
        _currentServerId.value = id
        refreshCurrent()
    }

    private fun refreshCurrent() {
        currentServer.value = _servers.value.firstOrNull { it.id == _currentServerId.value } ?: _servers.value.firstOrNull()
    }

    suspend fun setIconPrefix(v: String) { edit { it[K.ICON_PREFIX] = v }; iconPrefix.value = v }
    suspend fun setForwarding(v: Boolean) { edit { it[K.FWD] = v }; forwardingEnabled.value = v }
    suspend fun setCode(v: Boolean) { edit { it[K.CODE] = v }; codeEnabled.value = v }
    suspend fun setAdFilter(v: Boolean) { edit { it[K.AD] = v }; adFilterEnabled.value = v }
    suspend fun setSpecial(v: Boolean) { edit { it[K.SPECIAL] = v }; specialEnabled.value = v }
    suspend fun setSkipOngoing(v: Boolean) { edit { it[K.SKIP_ONGOING] = v }; skipOngoing.value = v }
    suspend fun setAdKeywords(list: List<String>) {
        edit { it[K.AD_KW] = json.encodeToString(list) }
        adKeywords.value = list
    }

    suspend fun snapshot() = ds.data.first()

    companion object {
        const val ID_OFFICIAL = "official"
    }
}
