package com.pixelized.desktop.lwa.ui.composable.character.purse

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.inventory.InventoryRepository
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
import com.pixelized.shared.lwa.model.inventory.Inventory
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update

class PurseDialogViewModel(
    private val inventoryRepository: InventoryRepository,
    private val factory: PurseDialogFactory,
) : ViewModel() {

    private val characterSheetIdFlow = MutableStateFlow<String?>(null)
    private val signFlow = MutableStateFlow(true)

    private val _error = MutableSharedFlow<ErrorSnackUio>()
    val error: MutableSharedFlow<ErrorSnackUio> = _error

    val purseDialog = characterSheetIdFlow.map { characterSheetId ->
        factory.convertToDialogUio(
            scope = viewModelScope,
            characterSheetId = characterSheetId,
            signFlow = signFlow,
        )
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.Lazily,
        initialValue = null,
    )

    fun showPurseDialog(
        characterSheetId: String?,
    ) {
        signFlow.value = true
        characterSheetIdFlow.value = characterSheetId
    }

    fun hidePurseDialog() {
        characterSheetIdFlow.value = null
    }

    fun swapPurseSign() {
        signFlow.update { it.not() }
    }

    suspend fun confirmPurse(dialog: PurseDialogUio): Boolean {
        // guard case: check if the dialog confirm state is enable
        if (dialog.enableConfirm.value.not()) {
            return false
        }
        // compute the new purse
        val sign = if (dialog.add.value) 1 else -1
        val goldValue = dialog.gold.valueFlow.value.toIntOrNull() ?: 0
        val silverValue = dialog.silver.valueFlow.value.toIntOrNull() ?: 0
        val copperValue = dialog.copper.valueFlow.value.toIntOrNull() ?: 0
        // guard case: check if the purse change, not an error case, but avoid useless API call.
        if (goldValue == 0 && silverValue == 0 && copperValue == 0) {
            return true
        }
        // build a purse delta
        val purse = Inventory.Purse(
            gold = goldValue * sign,
            silver = silverValue * sign,
            copper = copperValue * sign,
        )
        // API call.
        return try {
            inventoryRepository.updateInventoryPurse(
                characterSheetId = dialog.characterSheetId,
                purse = purse,
            )
            true
        } catch (exception: Exception) {
            val message = ErrorSnackUio.from(exception = exception)
            _error.emit(value = message)
            false
        }
    }
}