package com.meowarex.rlmobile.manager.base

import android.content.SharedPreferences
import androidx.compose.runtime.*
import androidx.core.content.edit
import kotlin.reflect.KProperty

abstract class BasePreferenceManager(
    private val prefs: SharedPreferences,
) {
    protected fun getString(key: String, defaultValue: String) = prefs.getString(key, defaultValue) ?: defaultValue
    private fun getBoolean(key: String, defaultValue: Boolean) = prefs.getBoolean(key, defaultValue)
    private fun getInt(key: String, defaultValue: Int) = prefs.getInt(key, defaultValue)
    private fun getFloat(key: String, defaultValue: Float) = prefs.getFloat(key, defaultValue)
    protected inline fun <reified E : Enum<E>> getEnum(key: String, defaultValue: E): E {
        return try {
            enumValueOf<E>(getString(key, defaultValue.name))
        } catch (_: IllegalArgumentException) {
            defaultValue
        }
    }

    protected fun putString(key: String, value: String?) = prefs.edit { putString(key, value) }
    private fun putBoolean(key: String, value: Boolean) = prefs.edit { putBoolean(key, value) }
    private fun putInt(key: String, value: Int) = prefs.edit { putInt(key, value) }
    private fun putFloat(key: String, value: Float) = prefs.edit { putFloat(key, value) }
    protected inline fun <reified E : Enum<E>> putEnum(key: String, value: E) = putString(key, value.name)

    protected class Preference<T>(
        private val key: String,
        defaultValue: T,
        getter: (key: String, defaultValue: T) -> T,
        private val setter: (key: String, newValue: T) -> Unit,
    ) {
        var value by mutableStateOf(getter(key, defaultValue))
            private set

        operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
        operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
            value = newValue
            setter(key, newValue)
        }
    }

    @Suppress("unused")
    protected fun stringPreference(
        key: String,
        defaultValue: String,
    ) = Preference(
        key = key,
        defaultValue = defaultValue,
        getter = ::getString,
        setter = ::putString
    )

    @Suppress("unused")
    protected fun booleanPreference(
        key: String,
        defaultValue: Boolean,
    ) = Preference(
        key = key,
        defaultValue = defaultValue,
        getter = ::getBoolean,
        setter = ::putBoolean
    )

    @Suppress("unused")
    protected fun intPreference(
        key: String,
        defaultValue: Int,
    ) = Preference(
        key = key,
        defaultValue = defaultValue,
        getter = ::getInt,
        setter = ::putInt
    )

    @Suppress("unused")
    protected fun floatPreference(
        key: String,
        defaultValue: Float,
    ) = Preference(
        key = key,
        defaultValue = defaultValue,
        getter = ::getFloat,
        setter = ::putFloat
    )

    @Suppress("unused")
    protected inline fun <reified E : Enum<E>> enumPreference(
        key: String,
        defaultValue: E,
    ) = Preference(
        key = key,
        defaultValue = defaultValue,
        getter = ::getEnum,
        setter = ::putEnum
    )
}
