package dev.privacyllc.period.feature.settings

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.privacyllc.period.core.data.CycleRepository
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

/** What the Privacy & Security section is doing right now. */
enum class DeletionState { IDLE, DELETING, DONE, FAILED }

/**
 * §45's Delete My Data.
 *
 * The deletion itself has existed since Batch 01 and had an instrumented test
 * before anything could call it. This adds the part a person touches, and the
 * three rules that make it a privacy control rather than a destructive button.
 *
 * ## It deletes health data and nothing else
 *
 * `UserPreferences` lives in `core/datastore`, a separate store from the cycle
 * database, and that separation exists for this moment: somebody exercising a
 * privacy control has not asked to have their notification privacy reset to a
 * default they did not choose. A user who wipes their history and is then sent
 * a Direct-mode reminder has been failed twice.
 *
 * ## It does not touch the reminder schedule
 *
 * Tempting, and wrong. `ReminderWorker` reads the forecast on each run, and
 * with no history `CycleStatusRules` returns `NoData`, which `ReminderRules`
 * maps to no decision — so the scheduled work already does nothing while there
 * is nothing to say. Cancelling it would be worse than pointless: scheduling
 * only happens from `ReminderCoordinator` and the notification settings screen,
 * so a cancel here would leave reminders silently off until the user next
 * toggled a setting, long after they had logged a new period.
 *
 * ## There is no undo
 *
 * §45 says irreversible after confirmation, and an undo snackbar keeps the data
 * alive for the length of its timeout — the opposite of what was just asked
 * for. The confirmation carries the whole weight, so it says plainly what goes
 * and what stays.
 */
@HiltViewModel
class PrivacyViewModel @Inject constructor(
    private val repository: CycleRepository,
) : ViewModel() {

    private val _deletion = MutableStateFlow(DeletionState.IDLE)
    val deletion: StateFlow<DeletionState> = _deletion.asStateFlow()

    /**
     * A failure surfaces instead of taking the process down.
     *
     * Batch 01's lesson, learned by tapping a button twice: a repository call
     * that throws inside `viewModelScope.launch` kills the app. Here it would
     * also leave the user unable to tell whether their data is gone, which is
     * the worst possible moment for an ambiguous outcome.
     */
    private val handler = CoroutineExceptionHandler { _, _ ->
        _deletion.value = DeletionState.FAILED
    }

    fun deleteEverything() {
        if (_deletion.value == DeletionState.DELETING) return
        _deletion.value = DeletionState.DELETING
        viewModelScope.launch(handler) {
            repository.deleteAllHealthData()
            _deletion.value = DeletionState.DONE
        }
    }

    fun acknowledge() {
        _deletion.value = DeletionState.IDLE
    }
}
