package cy.hexor.furumi.data.local

import android.content.Context
import cy.hexor.furumi.domain.model.OfflineSettings
import cy.hexor.furumi.domain.model.OfflineState
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class OfflineSettingsStorage @Inject constructor(
    @ApplicationContext context: Context
) {
    private val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
    private val _state = MutableStateFlow(loadState())

    val state: StateFlow<OfflineState> = _state.asStateFlow()

    fun setOfflineModeEnabled(enabled: Boolean) {
        prefs.edit().putBoolean(KEY_OFFLINE_MODE, enabled).apply()
        updateSettings { it.copy(offlineModeEnabled = enabled) }
    }

    fun setSaveListenedTracksEnabled(enabled: Boolean) {
        prefs.edit().putBoolean(KEY_SAVE_LISTENED, enabled).apply()
        updateSettings { it.copy(saveListenedTracksEnabled = enabled) }
    }

    fun setStorageLimitBytes(limitBytes: Long) {
        val safeLimit = limitBytes.coerceAtLeast(MIN_STORAGE_LIMIT_BYTES)
        prefs.edit().putLong(KEY_STORAGE_LIMIT_BYTES, safeLimit).apply()
        updateSettings { it.copy(storageLimitBytes = safeLimit) }
    }

    fun setSyncing(syncing: Boolean) {
        _state.value = _state.value.copy(isSyncing = syncing)
    }

    fun setLastSyncedAt(timestampMs: Long) {
        prefs.edit().putLong(KEY_LAST_SYNCED_AT_MS, timestampMs).apply()
        _state.value = _state.value.copy(lastSyncedAtMs = timestampMs, lastError = null)
    }

    fun setStorageStats(usedBytes: Long, cachedTrackCount: Int) {
        _state.value = _state.value.copy(
            storageUsedBytes = usedBytes.coerceAtLeast(0L),
            cachedTrackCount = cachedTrackCount.coerceAtLeast(0)
        )
    }

    fun setNetworkFallback(active: Boolean, errorMessage: String? = null) {
        _state.value = _state.value.copy(
            isUsingNetworkFallback = active,
            lastError = errorMessage ?: _state.value.lastError
        )
    }

    fun setLastError(message: String?) {
        _state.value = _state.value.copy(lastError = message)
    }

    private fun updateSettings(block: (OfflineSettings) -> OfflineSettings) {
        _state.value = _state.value.copy(settings = block(_state.value.settings))
    }

    private fun loadState(): OfflineState {
        return OfflineState(
            settings = OfflineSettings(
                offlineModeEnabled = prefs.getBoolean(KEY_OFFLINE_MODE, false),
                saveListenedTracksEnabled = prefs.getBoolean(KEY_SAVE_LISTENED, false),
                storageLimitBytes = prefs.getLong(
                    KEY_STORAGE_LIMIT_BYTES,
                    OfflineSettings.DEFAULT_STORAGE_LIMIT_BYTES
                )
            ),
            lastSyncedAtMs = prefs.getLong(KEY_LAST_SYNCED_AT_MS, 0L)
        )
    }

    private companion object {
        const val PREFS_NAME = "offline_settings"
        const val KEY_OFFLINE_MODE = "offline_mode"
        const val KEY_SAVE_LISTENED = "save_listened"
        const val KEY_STORAGE_LIMIT_BYTES = "storage_limit_bytes"
        const val KEY_LAST_SYNCED_AT_MS = "last_synced_at_ms"
        const val MIN_STORAGE_LIMIT_BYTES = 256L * 1024L * 1024L
    }
}
