package lu.rewardflow.terminal.data.repository

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Persisted device configuration.
 *
 * Once a tablet is paired (via QR scan on the setup screen) the merchant
 * server hands the device three pieces of data: an api_url, a store_code
 * and a long-lived auth_token. They live here for the entire lifetime of
 * the pairing — the token expires after 1 year and isn't refreshed.
 *
 * The cached *_json fields are populated after pairing so the PIN screen
 * and the terminal can render before the network round-trips on each
 * launch.
 */
@Singleton
class DeviceConfigRepository @Inject constructor(
    private val dataStore: DataStore<Preferences>,
) {

    // ── Flows (suspend collectors)
    val apiUrl: Flow<String?> = dataStore.data.map { it[KEY_API_URL] }
    val authToken: Flow<String?> = dataStore.data.map { it[KEY_AUTH_TOKEN] }
    val storeId: Flow<Int?> = dataStore.data.map { it[KEY_STORE_ID] }
    val storeCode: Flow<String?> = dataStore.data.map { it[KEY_STORE_CODE] }
    val storeName: Flow<String?> = dataStore.data.map { it[KEY_STORE_NAME] }
    val isDeviceSetUp: Flow<Boolean> = dataStore.data.map { it[KEY_IS_SET_UP] ?: false }

    val programJson: Flow<String?> = dataStore.data.map { it[KEY_PROGRAM_JSON] }
    val staffPinsJson: Flow<String?> = dataStore.data.map { it[KEY_STAFF_PINS_JSON] }
    val categoriesJson: Flow<String?> = dataStore.data.map { it[KEY_CATEGORIES_JSON] }

    // ── One-shot reads (when the call site is suspending and just needs
    //   the current value, e.g. an OkHttp interceptor or a repository fetch).
    suspend fun currentAuthToken(): String? = dataStore.data.first()[KEY_AUTH_TOKEN]
    suspend fun currentApiUrl(): String? = dataStore.data.first()[KEY_API_URL]
    suspend fun currentStoreId(): Int? = dataStore.data.first()[KEY_STORE_ID]
    suspend fun currentStoreCode(): String? = dataStore.data.first()[KEY_STORE_CODE]

    // ── Pairing: persist setup payload + cached config in a single transaction.
    suspend fun savePairing(
        apiUrl: String,
        authToken: String,
        storeId: Int,
        storeCode: String,
        storeName: String?,
    ) {
        dataStore.edit { prefs ->
            prefs[KEY_API_URL] = apiUrl
            prefs[KEY_AUTH_TOKEN] = authToken
            prefs[KEY_STORE_ID] = storeId
            prefs[KEY_STORE_CODE] = storeCode
            if (storeName != null) prefs[KEY_STORE_NAME] = storeName
            prefs[KEY_IS_SET_UP] = true
        }
    }

    suspend fun saveProgram(json: String) {
        dataStore.edit { it[KEY_PROGRAM_JSON] = json }
    }

    suspend fun saveStaffPins(json: String) {
        dataStore.edit { it[KEY_STAFF_PINS_JSON] = json }
    }

    suspend fun saveCategories(json: String) {
        dataStore.edit { it[KEY_CATEGORIES_JSON] = json }
    }

    /** Per-seller language preference, keyed by staff PIN id. */
    fun sellerLanguage(pinId: Int): Flow<String?> =
        dataStore.data.map { it[sellerLanguageKey(pinId)] }

    suspend fun saveSellerLanguage(pinId: Int, lang: String) {
        dataStore.edit { it[sellerLanguageKey(pinId)] = lang }
    }

    /**
     * Wipe the device back to factory state. The merchant has to re-pair
     * after this — the auth_token is gone, so the tablet can't call any
     * authenticated endpoint until a new QR is scanned.
     */
    suspend fun resetDevice() {
        dataStore.edit { it.clear() }
    }

    private fun sellerLanguageKey(pinId: Int) =
        stringPreferencesKey("seller_language_$pinId")

    companion object {
        private val KEY_API_URL = stringPreferencesKey("api_url")
        private val KEY_AUTH_TOKEN = stringPreferencesKey("auth_token")
        private val KEY_STORE_ID = intPreferencesKey("store_id")
        private val KEY_STORE_CODE = stringPreferencesKey("store_code")
        private val KEY_STORE_NAME = stringPreferencesKey("store_name")
        // Matches the key the existing SetupViewModel observed; keep this
        // exact string so the NavHost's start-destination switch works.
        private val KEY_IS_SET_UP = booleanPreferencesKey("is_device_set_up")
        private val KEY_PROGRAM_JSON = stringPreferencesKey("program_json")
        private val KEY_STAFF_PINS_JSON = stringPreferencesKey("staff_pins_json")
        private val KEY_CATEGORIES_JSON = stringPreferencesKey("categories_json")
    }
}
