package de.krisenvorrat.app.data.repository

import de.krisenvorrat.app.data.db.dao.SettingsDao
import de.krisenvorrat.app.data.db.entity.SettingsEntity
import de.krisenvorrat.app.data.security.SecureTokenStorage
import de.krisenvorrat.app.domain.model.SettingsKey
import de.krisenvorrat.app.domain.model.SettingsKeys
import de.krisenvorrat.app.domain.repository.SettingsRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import javax.inject.Inject

internal class SettingsRepositoryImpl @Inject constructor(
    private val dao: SettingsDao,
    private val secureTokenStorage: SecureTokenStorage
) : SettingsRepository {

    override suspend fun getValue(key: String): String? =
        if (key in SettingsKeys.SENSITIVE_KEYS) {
            withContext(Dispatchers.IO) { secureTokenStorage.get(key) }
        } else {
            withContext(Dispatchers.IO) { dao.getValue(key) }
        }

    override suspend fun setValue(key: String, value: String) =
        if (key in SettingsKeys.SENSITIVE_KEYS) {
            withContext(Dispatchers.IO) {
                if (value.isBlank()) {
                    secureTokenStorage.remove(key)
                } else {
                    secureTokenStorage.set(key, value)
                }
            }
        } else {
            withContext(Dispatchers.IO) { dao.upsert(SettingsEntity(key = key, value = value)) }
        }

    override fun observeValue(key: String): Flow<String?> = dao.observeValue(key)

    override fun getAll(): Flow<List<SettingsEntity>> = dao.getAll()

    override suspend fun getString(key: SettingsKey.StringKey): String =
        getValue(key.key) ?: key.defaultValue

    override suspend fun getStringOrNull(key: SettingsKey.StringKey): String? =
        getValue(key.key)

    override suspend fun setString(key: SettingsKey.StringKey, value: String) =
        setValue(key.key, value)

    override fun observeString(key: SettingsKey.StringKey): Flow<String> =
        observeValue(key.key).map { it ?: key.defaultValue }
}
