package com.jttools.datacontrol.data

import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.doublePreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton

private val Context.dataStore by preferencesDataStore(name = "datacontrol_settings")

@Singleton
class SettingsRepository @Inject constructor(
    @ApplicationContext private val context: Context
) {
    private object Keys {
        val CONTROL_ENABLED = booleanPreferencesKey("control_enabled")
        val PLAN_LIMIT_MO = longPreferencesKey("plan_limit_mo")
        val PLAN_PRICE_EURO = doublePreferencesKey("plan_price_euro")
        val OVERAGE_PRICE_PER_MO = doublePreferencesKey("overage_price_per_mo")
        val PLAN_START_DATE_EPOCH_DAY = longPreferencesKey("plan_start_date_epoch_day")
        val AUTO_RESET_ENABLED = booleanPreferencesKey("auto_reset_enabled")
        val CUTOFF_INTERVAL_MINUTES = intPreferencesKey("cutoff_interval_minutes")
        val BASELINE_MOBILE_BYTES = longPreferencesKey("baseline_mobile_bytes")
        val WHITELISTED_PACKAGES = stringSetPreferencesKey("whitelisted_packages")
        val WHITELISTED_PACKAGES_WIFI = stringSetPreferencesKey("whitelisted_packages_wifi")
        val WIFI_FILTER_ENABLED = booleanPreferencesKey("wifi_filter_enabled")
        val SHOW_SYSTEM_APPS = booleanPreferencesKey("show_system_apps")
        val PASSWORD_HASH = stringPreferencesKey("password_hash")
        val PASSWORD_SALT = stringPreferencesKey("password_salt")
        val CUTOFF_ANCHOR_MILLIS = longPreferencesKey("cutoff_anchor_millis")
        val CUTOFF_IN_PULSE = booleanPreferencesKey("cutoff_in_pulse")
        val CUTOFF_PULSE_START_MILLIS = longPreferencesKey("cutoff_pulse_start_millis")
    }

    val settingsFlow: Flow<AppSettings> = context.dataStore.data.map { prefs ->
        val defaults = AppSettings()
        AppSettings(
            controlEnabled = prefs[Keys.CONTROL_ENABLED] ?: defaults.controlEnabled,
            planLimitMo = prefs[Keys.PLAN_LIMIT_MO] ?: defaults.planLimitMo,
            planPriceEuro = prefs[Keys.PLAN_PRICE_EURO] ?: defaults.planPriceEuro,
            overagePricePerMoEuro = prefs[Keys.OVERAGE_PRICE_PER_MO] ?: defaults.overagePricePerMoEuro,
            planStartDateEpochDay = prefs[Keys.PLAN_START_DATE_EPOCH_DAY] ?: defaults.planStartDateEpochDay,
            autoResetEnabled = prefs[Keys.AUTO_RESET_ENABLED] ?: defaults.autoResetEnabled,
            cutoffIntervalMinutes = prefs[Keys.CUTOFF_INTERVAL_MINUTES] ?: defaults.cutoffIntervalMinutes,
            baselineMobileBytesAtReset = prefs[Keys.BASELINE_MOBILE_BYTES] ?: defaults.baselineMobileBytesAtReset,
            whitelistedPackages = prefs[Keys.WHITELISTED_PACKAGES] ?: defaults.whitelistedPackages,
            whitelistedPackagesWifi = prefs[Keys.WHITELISTED_PACKAGES_WIFI] ?: defaults.whitelistedPackagesWifi,
            wifiFilterEnabled = prefs[Keys.WIFI_FILTER_ENABLED] ?: defaults.wifiFilterEnabled,
            showSystemApps = prefs[Keys.SHOW_SYSTEM_APPS] ?: defaults.showSystemApps,
            passwordHash = prefs[Keys.PASSWORD_HASH],
            passwordSalt = prefs[Keys.PASSWORD_SALT],
            cutoffCycleAnchorMillis = prefs[Keys.CUTOFF_ANCHOR_MILLIS],
            cutoffInPulse = prefs[Keys.CUTOFF_IN_PULSE] ?: defaults.cutoffInPulse,
            cutoffPulseStartMillis = prefs[Keys.CUTOFF_PULSE_START_MILLIS] ?: defaults.cutoffPulseStartMillis
        )
    }

    suspend fun setControlEnabled(enabled: Boolean) {
        context.dataStore.edit { it[Keys.CONTROL_ENABLED] = enabled }
    }

    suspend fun updatePlan(
        planLimitMo: Long,
        planPriceEuro: Double,
        overagePricePerMoEuro: Double,
        cutoffIntervalMinutes: Int,
        autoResetEnabled: Boolean
    ) {
        context.dataStore.edit { prefs ->
            prefs[Keys.PLAN_LIMIT_MO] = planLimitMo
            prefs[Keys.PLAN_PRICE_EURO] = planPriceEuro
            prefs[Keys.OVERAGE_PRICE_PER_MO] = overagePricePerMoEuro
            prefs[Keys.CUTOFF_INTERVAL_MINUTES] = cutoffIntervalMinutes
            prefs[Keys.AUTO_RESET_ENABLED] = autoResetEnabled
        }
    }

    /** Change uniquement la date de début du cycle (référence pour le reset automatique), sans toucher au compteur en cours. */
    suspend fun setStartDate(date: LocalDate) {
        context.dataStore.edit { it[Keys.PLAN_START_DATE_EPOCH_DAY] = date.toEpochDay() }
    }

    suspend fun setWhitelistedPackages(packages: Set<String>) {
        context.dataStore.edit { it[Keys.WHITELISTED_PACKAGES] = packages }
    }

    suspend fun setWhitelistedPackagesWifi(packages: Set<String>) {
        context.dataStore.edit { it[Keys.WHITELISTED_PACKAGES_WIFI] = packages }
    }

    suspend fun setWifiFilterEnabled(enabled: Boolean) {
        context.dataStore.edit { it[Keys.WIFI_FILTER_ENABLED] = enabled }
    }

    suspend fun setShowSystemApps(show: Boolean) {
        context.dataStore.edit { it[Keys.SHOW_SYSTEM_APPS] = show }
    }

    /** Réinitialise le compteur de consommation : nouvelle date de début + nouvelle base de référence. */
    suspend fun resetPlan(currentMobileBytes: Long, startDate: LocalDate = LocalDate.now()) {
        context.dataStore.edit { prefs ->
            prefs[Keys.PLAN_START_DATE_EPOCH_DAY] = startDate.toEpochDay()
            prefs[Keys.BASELINE_MOBILE_BYTES] = currentMobileBytes
        }
    }

    /** Corrige la base de référence sans changer la date de début (ex: compteur système remis à zéro après redémarrage). */
    suspend fun rebaseline(currentMobileBytes: Long) {
        context.dataStore.edit { it[Keys.BASELINE_MOBILE_BYTES] = currentMobileBytes }
    }

    /**
     * Force la consommation affichée à [consumedMo] sans changer la date de début du cycle, en
     * recalculant la base de référence à partir du compteur système actuel ([currentTotalBytes]).
     * Utile pour recaler l'app sur le décompte opérateur réel.
     *
     * La base peut devenir négative (ex: valeur saisie supérieure au compteur TrafficStats depuis
     * le dernier redémarrage de l'appareil) : c'est volontaire, ne pas la borner à 0 sous peine
     * d'écraser silencieusement la valeur saisie par l'utilisateur. [UsageRepository.consumedBytesSince]
     * et [UsageRepository.hasCounterReset] gèrent correctement une base négative.
     */
    suspend fun setConsumedMo(consumedMo: Long, currentTotalBytes: Long) {
        val baseline = currentTotalBytes - UsageRepository.moToBytes(consumedMo)
        context.dataStore.edit { it[Keys.BASELINE_MOBILE_BYTES] = baseline }
    }

    /** Définit (ou supprime, si [password] est vide/null) le mot de passe de verrouillage. */
    suspend fun setPassword(password: String?) {
        if (password.isNullOrBlank()) {
            context.dataStore.edit {
                it.remove(Keys.PASSWORD_HASH)
                it.remove(Keys.PASSWORD_SALT)
            }
        } else {
            val salt = PasswordHasher.newSalt()
            val hash = PasswordHasher.hash(password, salt)
            context.dataStore.edit { prefs ->
                prefs[Keys.PASSWORD_HASH] = hash
                prefs[Keys.PASSWORD_SALT] = salt
            }
        }
    }

    /** Vrai si aucun mot de passe n'est défini, ou si [password] correspond au mot de passe stocké. */
    suspend fun verifyPassword(password: String): Boolean {
        val prefs = context.dataStore.data.first()
        val hash = prefs[Keys.PASSWORD_HASH] ?: return true
        val salt = prefs[Keys.PASSWORD_SALT] ?: return true
        return PasswordHasher.hash(password, salt) == hash
    }

    /**
     * Persiste l'état du cycle de coupure automatique, pour que le minuteur ne reparte pas de
     * zéro si [DataMonitorService] est tué puis relancé par le système avant la fin de l'intervalle
     * (fréquent sur les ROM qui tuent agressivement les apps en arrière-plan sans exemption batterie).
     */
    suspend fun setCutoffCycleState(anchorMillis: Long?, inPulse: Boolean, pulseStartMillis: Long) {
        context.dataStore.edit { prefs ->
            if (anchorMillis == null) prefs.remove(Keys.CUTOFF_ANCHOR_MILLIS) else prefs[Keys.CUTOFF_ANCHOR_MILLIS] = anchorMillis
            prefs[Keys.CUTOFF_IN_PULSE] = inPulse
            prefs[Keys.CUTOFF_PULSE_START_MILLIS] = pulseStartMillis
        }
    }
}
