package com.a2i.forwarder.core

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

@Serializable
data class ForwardLog(
    val time: Long,
    val pkg: String,
    val appLabel: String,
    val title: String?,
    val content: String,
    val status: String, // sent / filtered / failed
    val reason: String,
)

@Serializable
data class PendingPush(
    val id: String,
    val time: Long,
    val serverId: String,
    val messageJson: String,
)

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

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

    private object K {
        val LOGS = stringPreferencesKey("logs")
        val PENDING = stringPreferencesKey("pending")
        val SENT = intPreferencesKey("sent")
        val FILTERED = intPreferencesKey("filtered")
        val FAILED = intPreferencesKey("failed")
    }

    val logs = MutableStateFlow<List<ForwardLog>>(emptyList())
    val pending = MutableStateFlow<List<PendingPush>>(emptyList())
    val sentCount = MutableStateFlow(0)
    val filteredCount = MutableStateFlow(0)
    val failedCount = MutableStateFlow(0)

    init {
        scope.launch {
            ds.data.collect { p ->
                logs.value = p[K.LOGS]?.let { runCatching { json.decodeFromString<List<ForwardLog>>(it) }.getOrNull() } ?: emptyList()
                pending.value = p[K.PENDING]?.let { runCatching { json.decodeFromString<List<PendingPush>>(it) }.getOrNull() } ?: emptyList()
                sentCount.value = p[K.SENT] ?: 0
                filteredCount.value = p[K.FILTERED] ?: 0
                failedCount.value = p[K.FAILED] ?: 0
            }
        }
    }

    suspend fun addLog(l: ForwardLog) {
        val list = (listOf(l) + logs.value).take(300)
        ds.edit { it[K.LOGS] = json.encodeToString(list) }
        logs.value = list
        when (l.status) {
            "sent" -> ds.edit { it[K.SENT] = (sentCount.value + 1) }.also { sentCount.value += 1 }
            "filtered" -> ds.edit { it[K.FILTERED] = (filteredCount.value + 1) }.also { filteredCount.value += 1 }
            "failed" -> ds.edit { it[K.FAILED] = (failedCount.value + 1) }.also { failedCount.value += 1 }
        }
    }

    suspend fun clearLogs() {
        ds.edit { it.remove(K.LOGS) }
        logs.value = emptyList()
    }

    suspend fun resetCounters() {
        ds.edit { it[K.SENT] = 0; it[K.FILTERED] = 0; it[K.FAILED] = 0 }
        sentCount.value = 0; filteredCount.value = 0; failedCount.value = 0
    }

    suspend fun addPending(p: PendingPush) {
        val list = (pending.value + p).takeLast(100)
        ds.edit { it[K.PENDING] = json.encodeToString(list) }
        pending.value = list
    }

    suspend fun removePending(id: String) {
        val list = pending.value.filterNot { it.id == id }
        ds.edit { it[K.PENDING] = json.encodeToString(list) }
        pending.value = list
    }
}
