package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory

import com.pixelized.desktop.lwa.repository.inventory.InventoryRepository
import com.pixelized.desktop.lwa.repository.item.ItemRepository
import com.pixelized.desktop.lwa.ui.composable.character.inventory.InventoryDialogFactory
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
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.campaign.player.detail.inventory.item.InventoryItemUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.PurseUio
import com.pixelized.desktop.lwa.utils.extention.unAccent
import com.pixelized.shared.lwa.model.inventory.Inventory
import com.pixelized.shared.lwa.model.item.Item
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
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 lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character__inventory__filter_inventory__label
import org.jetbrains.compose.resources.getString
import java.text.Collator
import java.text.DecimalFormat

class CharacterDetailInventoryFactory(
    private val inventoryRepository: InventoryRepository,
    private val itemRepository: ItemRepository,
) {
    private val decimalFormat = DecimalFormat("#.##")

    fun addItemActionFlow(): Flow<Boolean> {
        return itemRepository.itemFlow().map { entry ->
            entry.values.any { item ->
                item.tags.any { id -> id == ADDABLE_TAG_ID }
            }
        }
    }

    suspend fun convertToCharacterInventoryUioFlow(
        characterSheetId: String,
        scope: CoroutineScope,
        started: SharingStarted = SharingStarted.Eagerly,
        addItemAction: StateFlow<Boolean>,
        initialValue: () -> CharacterDetailInventoryUio?,
    ): StateFlow<CharacterDetailInventoryUio?> {
        val showFilterFlow = MutableStateFlow(false)
        val filterFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character__inventory__filter_inventory__label),
            value = "",
        )
        return combine(
            inventoryRepository.inventoryFlow(characterSheetId = characterSheetId),
            itemRepository.itemFlow(),
            filterFlow.valueFlow.map { it.unAccent() },
        ) { inventory, items, filter ->
            convertToCharacterInventoryUio(
                characterSheetId = characterSheetId,
                showFilter = showFilterFlow,
                filter = filterFlow.createLwaTextField(),
                addItemAction = addItemAction,
                purse = inventory.purse,
                inventory = inventory.items,
                items = items.filterValues { it.metadata.label.unAccent().contains(filter, true) },
            )
        }.stateIn(
            scope = scope,
            started = started,
            initialValue = initialValue(),
        )
    }

    private fun convertToCharacterInventoryUio(
        characterSheetId: String?,
        showFilter: StateFlow<Boolean>,
        filter: LwaTextFieldUio,
        addItemAction: StateFlow<Boolean>,
        purse: Inventory.Purse?,
        inventory: List<Inventory.Item>?,
        items: Map<String, Item>,
    ): CharacterDetailInventoryUio? {
        if (characterSheetId == null) return null

        return CharacterDetailInventoryUio(
            characterSheetId = characterSheetId,
            purse = PurseUio(
                gold = purse?.gold ?: 0,
                silver = purse?.silver ?: 0,
                copper = purse?.copper ?: 0,
            ),
            showFilter = showFilter,
            filter = filter,
            addItemAction = addItemAction,
            items = inventory
                ?.mapNotNull {
                    val item = items[it.itemId] ?: return@mapNotNull null
                    InventoryItemUio(
                        characterSheetId = characterSheetId,
                        inventoryId = it.inventoryId,
                        itemId = it.itemId,
                        icon = item.metadata.thumbnail ?: item.metadata.image,
                        label = item.metadata.label,
                        count = decimalFormat.format(it.count),
                        equipped = it.equipped,
                        stackable = item.options.stackable,
                        consumable = item.options.consumable,
                        equipable = item.options.equipable,
                        tooltips = takeIf { item.metadata.description.isNotEmpty() }?.let {
                            InventoryItemUio.Tooltips(
                                label = item.metadata.label,
                                description = item.metadata.description,
                                image = item.metadata.image,
                            )
                        }
                    )
                }
                ?.sortedWith(compareBy(Collator.getInstance()) { it.label })
                ?.sortedByDescending { it.equipped }
                ?: emptyList()
        )
    }

    companion object {
        private const val ADDABLE_TAG_ID = InventoryDialogFactory.ADDABLE_TAG_ID
    }
}