package com.github.nullptroma.wallenc.ui.screens.main.screens.storage

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.github.nullptroma.wallenc.domain.datatypes.StorageMetaLoadState
import com.github.nullptroma.wallenc.domain.errors.WallencException
import com.github.nullptroma.wallenc.ui.R
import com.github.nullptroma.wallenc.ui.ViewModelBase
import com.github.nullptroma.wallenc.ui.resources.UserNotification
import com.github.nullptroma.wallenc.ui.resources.toUserNotification
import com.github.nullptroma.wallenc.usecases.FindStorageUseCase
import com.github.nullptroma.wallenc.usecases.ManageTextSecretsUseCase
import com.github.nullptroma.wallenc.usecases.ManageTwoFaTokensUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class StorageHomeViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
    private val findStorageUseCase: FindStorageUseCase,
    private val manageTwoFaTokensUseCase: ManageTwoFaTokensUseCase,
    private val manageTextSecretsUseCase: ManageTextSecretsUseCase,
) : ViewModelBase<StorageHomeScreenState>(StorageHomeScreenState()) {

    private val storageUuid = savedStateHandle.requireStorageUuid()

    init {
        observeStorageState()
    }

    private fun observeStorageState() {
        viewModelScope.launch {
            val storage = findStorageUseCase.find(storageUuid)
            if (storage == null) {
                updateState(
                    state.value.copy(
                        isLoading = false,
                        storageUuid = storageUuid.toString(),
                        errorNotification = WallencException.Feature.StorageNotFound().toUserNotification(),
                    ),
                )
                return@launch
            }
            combine(
                storage.isAvailable,
                storage.metaInfo,
                storage.metaLoadState,
                manageTwoFaTokensUseCase.observe(storage),
                manageTextSecretsUseCase.observe(storage),
            ) { available, meta, metaState, twoFa, secrets ->
                val metaUnavailable = metaState == StorageMetaLoadState.Unavailable
                val isRawEncrypted = meta.encInfo != null && !storage.isVirtualStorage
                val canManageDomainData = available && !isRawEncrypted && !metaUnavailable
                state.value.copy(
                    isLoading = false,
                    storageUuid = storage.uuid.toString(),
                    storageName = meta.name.orEmpty(),
                    isAvailable = available,
                    isEncrypted = meta.encInfo != null,
                    isVirtualStorage = storage.isVirtualStorage,
                    twoFaCount = twoFa.size,
                    textSecretsCount = secrets.size,
                    canManageDomainData = canManageDomainData,
                    errorNotification = when {
                        metaUnavailable -> UserNotification.TextRes(R.string.storage_home_meta_unavailable)
                        isRawEncrypted -> WallencException.Feature.NeedsDecryptedView().toUserNotification()
                        else -> null
                    },
                )
            }.collect { ui ->
                updateState(ui)
            }
        }
    }
}
