package ca.ksamad.encore.data

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

// A single process-wide DataStore instance, tied to the application context via
// this property delegate (the recommended pattern — creating more than one
// DataStore for the same file throws).
private val Context.dataStore: DataStore<Preferences> by
    preferencesDataStore(name = "connection_settings")

/**
 * Reads and writes the persisted [ConnectionSettings] using Preferences DataStore. Reads come back
 * as a [Flow] that emits on every change; the write is a `suspend` transaction.
 */
class SettingsRepository(private val context: Context) {
    private object Keys {
        val HOST = stringPreferencesKey("host")
        val PORT = intPreferencesKey("port")
        val PASSWORD = stringPreferencesKey("password")
        val ALBUM_VIEW_MODE = stringPreferencesKey("album_view_mode")
    }

    /** How the albums library is laid out; emits on every change, defaulted when unset. */
    val albumViewMode: Flow<AlbumViewMode> =
        context.dataStore.data.map { prefs -> AlbumViewMode.fromName(prefs[Keys.ALBUM_VIEW_MODE]) }

    suspend fun setAlbumViewMode(mode: AlbumViewMode) {
        context.dataStore.edit { prefs -> prefs[Keys.ALBUM_VIEW_MODE] = mode.name }
    }

    /**
     * The saved settings, or `null` if the user has never connected (no host persisted yet).
     * Callers use the null case to show first-run UI / decide whether to auto-connect.
     */
    val settingsOrNull: Flow<ConnectionSettings?> =
        context.dataStore.data.map { prefs ->
            val host = prefs[Keys.HOST] ?: return@map null
            ConnectionSettings(
                host = host,
                port = prefs[Keys.PORT] ?: ConnectionSettings.DEFAULT.port,
                password = prefs[Keys.PASSWORD],
            )
        }

    /**
     * Same as [settingsOrNull] but falling back to [ConnectionSettings.DEFAULT] for form prefill.
     */
    val settings: Flow<ConnectionSettings> = settingsOrNull.map { it ?: ConnectionSettings.DEFAULT }

    suspend fun save(settings: ConnectionSettings) {
        context.dataStore.edit { prefs ->
            prefs[Keys.HOST] = settings.host
            prefs[Keys.PORT] = settings.port
            // Drop the key entirely for a password-less server so we never persist a
            // stray empty string (and a later read comes back as null, not "").
            val pw = settings.password
            if (pw.isNullOrBlank()) prefs.remove(Keys.PASSWORD) else prefs[Keys.PASSWORD] = pw
        }
    }

    /** Forget all persisted settings, returning to first-run defaults. */
    suspend fun clear() {
        context.dataStore.edit { it.clear() }
    }
}
