package com.pixelized.desktop.lwa.ui.screen.admin.alteration.list

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
import com.pixelized.desktop.lwa.repository.tag.TagRepository
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextField
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextFieldFlow
import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagFactory
import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagUio
import com.pixelized.desktop.lwa.utils.extention.unAccent
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.runBlocking
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.game_master__character__filter
import org.jetbrains.compose.resources.getString

class GMAlterationViewModel(
    private val alterationRepository: AlterationRepository,
    alterationFactory: GMAlterationFactory,
    tagRepository: TagRepository,
    tagFactory: GMTagFactory,
) : ViewModel() {

    private val selectedTagId = MutableStateFlow<String?>(null)

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

    private val _filter = createLwaTextFieldFlow(
        label = runBlocking { getString(Res.string.game_master__character__filter) },
    )
    val filter = _filter.createLwaTextField()

    val tags: StateFlow<List<GMTagUio>> = combine(
        tagRepository.alterationsTagFlow(),
        selectedTagId,
    ) { tags, selectedTagId ->
        tagFactory.convertToGMTagItemUio(
            tags = tags.values,
            selectedTagId = selectedTagId,
        )
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.Lazily,
        initialValue = emptyList(),
    )

    val alterations: StateFlow<List<GMAlterationUio>> = combine(
        alterationRepository.alterationFlow,
        tagRepository.alterationsTagFlow(),
        filter.valueFlow.map { it.unAccent() },
        selectedTagId,
    ) { alterations, tags, unAccentFilter, selectedTagId ->
        alterationFactory.convertToGMAlterationUio(
            alterations = alterationFactory.filterAlteration(
                alterations = alterations.values,
                unAccentFilter = unAccentFilter,
                selectedTagId = selectedTagId,
            ),
            tags = tags,
            selectedTagId = selectedTagId,
        )
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.Lazily,
        initialValue = emptyList(),
    )

    fun onTag(id: String) {
        selectedTagId.update {
            when (it) {
                id -> null
                else -> id
            }
        }
    }

    suspend fun deleteAlteration(alterationId: String) {
        try {
            alterationRepository.deleteAlteration(
                alterationId = alterationId,
            )
        } catch (exception: Exception) {
            val message = ErrorSnackUio.from(exception = exception)
            _error.emit(message)
        }
    }
}