package com.example.filedrop

import android.app.Application
import android.net.Uri
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

enum class UploadStatus { PENDING, UPLOADING, DONE, ERROR }

data class UploadItem(
    val uri: Uri,
    val name: String,
    val size: Long,
    val progress: Float = 0f,
    val status: UploadStatus = UploadStatus.PENDING,
    val error: String? = null,
)

class MainViewModel(app: Application) : AndroidViewModel(app) {

    private val settings = Settings(app)
    private val uploader = Uploader(app.contentResolver)

    val address: StateFlow<String> = settings.address
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), "")
    val token: StateFlow<String> = settings.token
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), "")

    private val _items = MutableStateFlow<List<UploadItem>>(emptyList())
    val items: StateFlow<List<UploadItem>> = _items

    private val _message = MutableStateFlow<String?>(null)
    val message: StateFlow<String?> = _message

    fun setAddress(value: String) = viewModelScope.launch { settings.setAddress(value) }
    fun setToken(value: String) = viewModelScope.launch { settings.setToken(value) }
    fun messageShown() { _message.value = null }

    fun onFilesPicked(uris: List<Uri>) {
        val picked = uris.map { uri ->
            val meta = uploader.queryMeta(uri)
            UploadItem(uri = uri, name = meta.name, size = meta.size)
        }
        _items.value = picked
        uploadAll()
    }

    fun retry(uri: Uri) = uploadOne(uri)

    private fun uploadAll() {
        _items.value.forEach { uploadOne(it.uri) }
    }

    private fun uploadOne(uri: Uri) {
        val addr = address.value
        if (addr.isBlank()) {
            _message.value = "Set the PC address first"
            return
        }
        val item = _items.value.firstOrNull { it.uri == uri } ?: return
        update(uri) { it.copy(status = UploadStatus.UPLOADING, progress = 0f, error = null) }

        viewModelScope.launch {
            val result = uploader.upload(
                address = addr,
                token = token.value,
                uri = uri,
                meta = FileMeta(item.name, item.size),
                onProgress = { fraction ->
                    if (fraction >= 0f) update(uri) { it.copy(progress = fraction) }
                },
            )
            result.onSuccess {
                update(uri) { it.copy(status = UploadStatus.DONE, progress = 1f) }
                _message.value = "Sent ${item.name}"
            }.onFailure { e ->
                update(uri) { it.copy(status = UploadStatus.ERROR, error = e.message) }
                _message.value = "Failed ${item.name}: ${e.message}"
            }
        }
    }

    private fun update(uri: Uri, transform: (UploadItem) -> UploadItem) {
        _items.value = _items.value.map { if (it.uri == uri) transform(it) else it }
    }
}
