package de.ladkau.deckinadash.data

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.doublePreferencesKey
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.flow.Flow
import kotlinx.coroutines.flow.map

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

/** Preferences DataStore-backed persistence for [DeckConfig] - see that
 * class's own doc comment for why DataStore over SharedPreferences/Proto
 * DataStore. */
class ConfigRepository(private val context: Context) {
    private object Keys {
        val CONFIGURED = booleanPreferencesKey("configured")
        val BIRTH_YEAR = intPreferencesKey("birth_year")
        val BIRTH_MONTH = intPreferencesKey("birth_month")
        val BIRTH_DAY = intPreferencesKey("birth_day")
        val BIRTH_HOUR = intPreferencesKey("birth_hour")
        val BIRTH_MINUTE = intPreferencesKey("birth_minute")
        val UTC_OFFSET_HOURS = doublePreferencesKey("utc_offset_hours")
        val LATITUDE = doublePreferencesKey("latitude")
        val LONGITUDE = doublePreferencesKey("longitude")
        val GENDER = stringPreferencesKey("gender")
        val LANG = stringPreferencesKey("lang")
        val NOTIFY_ENABLED = booleanPreferencesKey("notify_enabled")
        val NOTIFY_HOUR = intPreferencesKey("notify_hour")
        val NOTIFY_MINUTE = intPreferencesKey("notify_minute")
    }

    val config: Flow<DeckConfig> = context.configDataStore.data.map { prefs ->
        DeckConfig(
            configured = prefs[Keys.CONFIGURED] ?: false,
            birthYear = prefs[Keys.BIRTH_YEAR] ?: 0,
            birthMonth = prefs[Keys.BIRTH_MONTH] ?: 0,
            birthDay = prefs[Keys.BIRTH_DAY] ?: 0,
            birthHour = prefs[Keys.BIRTH_HOUR] ?: 0,
            birthMinute = prefs[Keys.BIRTH_MINUTE] ?: 0,
            utcOffsetHours = prefs[Keys.UTC_OFFSET_HOURS] ?: 0.0,
            latitude = prefs[Keys.LATITUDE] ?: 0.0,
            longitude = prefs[Keys.LONGITUDE] ?: 0.0,
            gender = prefs[Keys.GENDER]?.let { Gender.valueOf(it) } ?: Gender.UNSPECIFIED,
            lang = prefs[Keys.LANG] ?: "en",
            notifyEnabled = prefs[Keys.NOTIFY_ENABLED] ?: false,
            notifyHour = prefs[Keys.NOTIFY_HOUR] ?: 8,
            notifyMinute = prefs[Keys.NOTIFY_MINUTE] ?: 0,
        )
    }

    suspend fun save(config: DeckConfig) {
        context.configDataStore.edit { prefs ->
            prefs[Keys.CONFIGURED] = true
            prefs[Keys.BIRTH_YEAR] = config.birthYear
            prefs[Keys.BIRTH_MONTH] = config.birthMonth
            prefs[Keys.BIRTH_DAY] = config.birthDay
            prefs[Keys.BIRTH_HOUR] = config.birthHour
            prefs[Keys.BIRTH_MINUTE] = config.birthMinute
            prefs[Keys.UTC_OFFSET_HOURS] = config.utcOffsetHours
            prefs[Keys.LATITUDE] = config.latitude
            prefs[Keys.LONGITUDE] = config.longitude
            prefs[Keys.GENDER] = config.gender.name
            prefs[Keys.LANG] = config.lang
            prefs[Keys.NOTIFY_ENABLED] = config.notifyEnabled
            prefs[Keys.NOTIFY_HOUR] = config.notifyHour
            prefs[Keys.NOTIFY_MINUTE] = config.notifyMinute
        }
    }
}
