package dev.privacyllc.period.feature.export

import android.net.Uri
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
import javax.inject.Singleton

/** Where an export has got to. One shot, cleared when the user acknowledges it. */
enum class ExportOutcome {
    IDLE,

    /** The user picked a destination while the app was locked. Nothing is written yet. */
    PENDING_UNLOCK,

    WRITING,

    DONE,

    /** Failed, and the empty file the picker created was cleaned up. */
    FAILED,

    /**
     * Failed, and a partial or empty file is still sitting at the destination.
     *
     * Its own outcome because the user has something to do about it, and
     * because "nothing happened" and "a broken file is in your Drive" must not
     * read the same.
     */
    FAILED_PARTIAL_FILE,
}

/**
 * The export's state, held for as long as the process rather than a screen.
 *
 * Same shape and same reason as `AppLockController`. Picking a destination
 * leaves the app for another app's UI, and coming back can re-lock — which
 * clears every nav-scoped ViewModel. State that lived in one would be gone
 * exactly when the result arrives, so a user would return to a screen that had
 * forgotten it asked.
 *
 * Nothing here is persisted. A destination the user chose before killing the app
 * is not a destination they still want, and reviving it silently later would be
 * a write they did not ask for.
 */
@Singleton
class ExportController @Inject constructor() {

    private val _outcome = MutableStateFlow(ExportOutcome.IDLE)
    val outcome: StateFlow<ExportOutcome> = _outcome.asStateFlow()

    /** Non-null when a picker should be opened, carrying the suggested file name. */
    private val _launchRequest = MutableStateFlow<String?>(null)
    val launchRequest: StateFlow<String?> = _launchRequest.asStateFlow()

    /** Where the user chose to put it. Held until the session is unlocked. */
    private val _destination = MutableStateFlow<Uri?>(null)
    val destination: StateFlow<Uri?> = _destination.asStateFlow()

    fun requestPicker(fileName: String) {
        _outcome.value = ExportOutcome.IDLE
        _launchRequest.value = fileName
    }

    /** Consumed by the activity once the picker is open. */
    fun onPickerLaunched() {
        _launchRequest.value = null
    }

    /**
     * The picker came back.
     *
     * A null uri is a cancellation, and cancelling says nothing at all — no
     * message, no state. The user changed their mind, which is not an event.
     */
    fun onDestination(uri: Uri?) {
        if (uri == null) {
            _outcome.value = ExportOutcome.IDLE
            return
        }
        _destination.value = uri
        _outcome.value = ExportOutcome.PENDING_UNLOCK
    }

    /**
     * Take the destination, once, to write it.
     *
     * Cleared as it is handed over so a relock/unlock cycle cannot write the
     * same export twice — a second write into a document the user has already
     * received is at best confusing and at worst a file they thought was
     * finished changing under them.
     */
    fun takeDestination(): Uri? = _destination.value.also { _destination.value = null }

    fun onWriting() {
        _outcome.value = ExportOutcome.WRITING
    }

    fun onDone() {
        _outcome.value = ExportOutcome.DONE
    }

    fun onFailed(partialFileLeft: Boolean) {
        _outcome.value =
            if (partialFileLeft) ExportOutcome.FAILED_PARTIAL_FILE else ExportOutcome.FAILED
    }

    fun acknowledge() {
        _outcome.value = ExportOutcome.IDLE
    }
}
