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 SHOW_SYSTEM_APPS = booleanPreferencesKey("show_system_apps")
        val PASSWORD_HASH = stringPreferencesKey("password_hash")
        val PASSWORD_SALT = stringPreferencesKey("password_salt")
    }

    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,
            showSystemApps = prefs[Keys.SHOW_SYSTEM_APPS] ?: defaults.showSystemApps,
            passwordHash = prefs[Keys.PASSWORD_HASH],
            passwordSalt = prefs[Keys.PASSWORD_SALT]
        )
    }

    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 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 }
    }

    /** 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
    }
}
