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

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.repository.tag.TagRepository
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.character.list.GMCharacterItemUio.Action
import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagFactory
import com.pixelized.desktop.lwa.utils.extention.unAccent
import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
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
import java.awt.Desktop

class GMCharacterViewModel(
    private val networkRepository: NetworkRepository,
    private val campaignRepository: CampaignRepository,
    private val characterSheetRepository: CharacterSheetRepository,
    tagRepository: TagRepository,
    private val factory: GMCharacterFactory,
    private val tagFactory: GMTagFactory,
) : ViewModel() {

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

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

    val tags = combine(
        tagRepository.charactersTagFlow(),
        selectedTagId,
    ) { tags, selectedTagId ->
        tagFactory.convertToGMTagItemUio(
            tags = tags.values,
            selectedTagId = selectedTagId,
        )
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.Lazily,
        initialValue = emptyList(),
    )

    val characters = combine(
        campaignRepository.campaignFlow(),
        characterSheetRepository.characterSheetPreviewFlow(),
        filter.valueFlow.map { it.unAccent() },
        tags.map { tags -> tags.associateBy { it.id } },
        selectedTagId,
    ) { campaign, characters, unAccentFilter, tagIdMap, selectedTagId ->
        factory.convertToGMCharacterPreviewUio(
            characters = factory.filterCharacter(
                campaign = campaign,
                characters = characters,
                unAccentFilter = unAccentFilter,
                selectedTagId = selectedTagId,
            ),
            campaign = campaign,
            tagIdMap = tagIdMap,
        )
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.Eagerly,
        initialValue = emptyList(),
    )

    fun onCharacterAction(
        characterSheetId: String,
        action: Action,
    ) {
        viewModelScope.launch {
            try {
                when (action) {
                    is Action.DisplayPortrait -> networkRepository.share(
                        GameMasterEvent.DisplayPortrait(
                            timestamp = System.currentTimeMillis(),
                            characterSheetId = characterSheetId,
                        )
                    )

                    is Action.ExternalLink -> {
                        if (Desktop.isDesktopSupported()) {
                            val desktop = Desktop.getDesktop()
                            if (desktop.isSupported(Desktop.Action.BROWSE)) {
                                desktop.browse(action.externalLink)
                            }
                        }
                    }

                    is Action.AddToGroup -> campaignRepository.addCharacter(
                        characterSheetId = characterSheetId,
                    )

                    is Action.AddToNpc -> campaignRepository.addNpc(
                        characterSheetId = characterSheetId,
                    )

                    is Action.RemoveFromGroup -> campaignRepository.removeCharacter(
                        characterSheetId = characterSheetId,
                    )

                    is Action.RemoveFromNpc -> campaignRepository.removeNpc(
                        characterSheetId = characterSheetId,
                    )

                    is Action.DeleteCharacter -> characterSheetRepository.deleteCharacter(
                        characterSheetId = action.characterSheetId,
                    )
                }
            } catch (exception: Exception) {
                // TODO proper exception handling
            }
        }
    }

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