package com.pixelized.desktop.lwa.ui.screen.admin.item.edit

import com.pixelized.desktop.lwa.ui.composable.checkbox.LwaCheckBoxUio
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.shared.lwa.model.alteration.Alteration
import com.pixelized.shared.lwa.model.item.Item
import com.pixelized.shared.lwa.model.tag.Tag
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.stateIn
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.game_master__item__edit_description
import lwacharactersheet.composeapp.generated.resources.game_master__item__edit_id
import lwacharactersheet.composeapp.generated.resources.game_master__item__edit_image
import lwacharactersheet.composeapp.generated.resources.game_master__item__edit_label
import lwacharactersheet.composeapp.generated.resources.game_master__item__edit_thumbnail
import org.jetbrains.compose.resources.getString

class GMItemEditFactory(
    private val tagFactory: GMTagFactory,
) {
    suspend fun createForm(
        item: Item?,
        tags: Collection<Tag>,
        alterationFlow: StateFlow<Map<String, Alteration>>,
    ): GMItemEditViewModel.GMItemEditForm {
        val idFlow = createLwaTextFieldFlow(
            label = getString(Res.string.game_master__item__edit_id),
            value = item?.id ?: "",
        )
        val labelFlow = createLwaTextFieldFlow(
            label = getString(Res.string.game_master__item__edit_label),
            value = item?.metadata?.label ?: "",
        )
        val descriptionFlow = createLwaTextFieldFlow(
            label = getString(Res.string.game_master__item__edit_description),
            value = item?.metadata?.description ?: "",
        )
        val imageFlow = createLwaTextFieldFlow(
            label = getString(Res.string.game_master__item__edit_image),
            value = item?.metadata?.image ?: "",
        )
        val thumbnailFlow = createLwaTextFieldFlow(
            label = getString(Res.string.game_master__item__edit_thumbnail),
            value = item?.metadata?.thumbnail ?: "",
        )
        val stackableFlow = MutableStateFlow(value = item?.options?.stackable ?: false)
        val equipableFlow = MutableStateFlow(value = item?.options?.equipable ?: false)
        val consumableFlow = MutableStateFlow(value = item?.options?.consumable ?: false)
        val tagFlow = MutableStateFlow(
            tagFactory.convertToGMTagItemUio(
                tags = tags,
                selectedTagIds = item?.tags ?: emptyList(),
            )
        )
        val alterations = MutableStateFlow(
            item?.alterations
                ?.associate { alterationId ->
                    val field = GMItemEditViewModel.GMItemEditForm.GMAlterationFieldItemFlow(
                        errorFlow = MutableStateFlow(null),
                        valueFlow = MutableStateFlow(alterationId)
                    )
                    field.key to field
                }
                ?: emptyMap()
        )
        return GMItemEditViewModel.GMItemEditForm(
            idFlow = idFlow,
            labelFlow = labelFlow,
            descriptionFlow = descriptionFlow,
            imageFlow = imageFlow,
            thumbnailFlow = thumbnailFlow,
            stackableFlow = stackableFlow,
            equipableFlow = equipableFlow,
            consumableFlow = consumableFlow,
            tagFlow = tagFlow,
            alterationsFlow = alterations,
        )
    }

    fun createPage(
        scope: CoroutineScope,
        originId: String?,
        alterations: Map<String, Alteration>,
        form: GMItemEditViewModel.GMItemEditForm,
    ): GMItemEditPageUio {
        return GMItemEditPageUio(
            id = form.idFlow.createLwaTextField(enable = originId == null),
            label = form.labelFlow.createLwaTextField(),
            description = form.descriptionFlow.createLwaTextField(),
            image = form.imageFlow.createLwaTextField(),
            thumbnail = form.thumbnailFlow.createLwaTextField(),
            equipable = LwaCheckBoxUio(
                checked = form.equipableFlow,
                onCheckedChange = { form.equipableFlow.value = it },
            ),
            stackable = LwaCheckBoxUio(
                checked = form.stackableFlow,
                onCheckedChange = { form.stackableFlow.value = it },
            ),
            consumable = LwaCheckBoxUio(
                checked = form.consumableFlow,
                onCheckedChange = { form.consumableFlow.value = it },
            ),
            alterations = form.alterationsFlow.map { data ->
                data.map { entry ->
                    createAlterationUio(
                        key = entry.key,
                        value = entry.value.valueFlow.mapNotNull { alterationId ->
                            if (alterationId == null) return@mapNotNull null
                            val alteration = alterations[alterationId] ?: return@mapNotNull null
                            GMAlterationFieldItemUio.Field(
                                id = alterationId,
                                label = alteration.metadata.name,
                            )
                        }.stateIn(
                            scope = scope,
                            started = SharingStarted.Eagerly,
                            initialValue = null,
                        ),
                        error = entry.value.errorFlow,
                        alterations = alterations.values,
                    )
                }
            }.stateIn(
                scope = scope,
                started = SharingStarted.Eagerly,
                initialValue = emptyList(),
            ),
            tags = form.tagFlow,
        )
    }

    fun createItem(
        form: GMItemEditViewModel.GMItemEditForm?,
    ): Item? {
        if (form == null) return null
        return Item(
            id = form.idFlow.valueFlow.value,
            metadata = Item.MetaData(
                label = form.labelFlow.valueFlow.value,
                description = form.descriptionFlow.valueFlow.value,
                image = form.imageFlow.valueFlow.value,
                thumbnail = form.thumbnailFlow.valueFlow.value,
            ),
            options = Item.Options(
                stackable = form.stackableFlow.value,
                equipable = form.equipableFlow.value,
                consumable = form.consumableFlow.value,
            ),
            tags = form.tagFlow.value
                .filter { it.highlight }
                .map { it.id },
            alterations = form.alterationsFlow.value.values
                .mapNotNull { it.valueFlow.value },
        )
    }

    fun createAlterationUio(
        key: String,
        value: StateFlow<GMAlterationFieldItemUio.Field?>,
        error: StateFlow<String?>,
        alterations: Collection<Alteration>,
    ): GMAlterationFieldItemUio {
        return GMAlterationFieldItemUio(
            key = key,
            value = value,
            error = error,
            menu = alterations.map { alteration ->
                createAlterationFieldUio(alteration)
            },
        )
    }

    private fun createAlterationFieldUio(
        alteration: Alteration,
    ): GMAlterationFieldItemUio.Field {
        return GMAlterationFieldItemUio.Field(
            id = alteration.id,
            label = alteration.metadata.name,
        )
    }
}