package com.pixelized.desktop.lwa.ui.screen.admin.character.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.character.edit.item.GMActionFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMSkillFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagFactory
import com.pixelized.desktop.lwa.utils.extention.unpack
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.ACROBATICS_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.AID_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.ATHLETICS_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.BARGAIN_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.COMBAT_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.DISCRETION_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.DODGE_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.EMPATHY_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.GRAB_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.INTIMIDATION_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.PERCEPTION_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.PERSUASION_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.SEARCH_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.SPIEL_ID
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.THROW_ID
import com.pixelized.shared.lwa.model.tag.Tag
import com.pixelized.shared.lwa.usecase.SkillUseCase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__critical_action_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__default_action_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__description_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__id_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__name_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__spacial_action_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__cha
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__con
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__dex
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__hei
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__int
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__level
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__portrait
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__pow
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__str
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__thumbnail
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__external_link
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__id_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__job
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__name_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__base_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bonus_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__description_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__id_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__level_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__name_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_label
import org.jetbrains.compose.resources.getString
import java.util.UUID

class GMCharacterEditFactory(
    private val tagFactory: GMTagFactory,
    private val skillUseCase: SkillUseCase,
) {
    suspend fun convertIntoModel(
        sheet: CharacterSheet?,
        form: GMCharacterEditPageUio,
    ): CharacterSheet {
        return CharacterSheet(
            id = form.characterSheetId.unpack()
                ?: error("Missing characterSheetId"),
            name = form.name.unpack()
                ?: error("Missing character name"),
            job = form.job.unpack() ?: "",
            portrait = form.portrait.unpack(),
            thumbnail = form.thumbnail.unpack(),
            externalLink = form.externalLink.unpack(),
            level = form.level.unpack()
                ?: error("Missing character level"),
            shouldLevelUp = form.levelUp.checked.value,
            strength = form.characteristics.strength.unpack()
                ?: error("Missing character strength"),
            dexterity = form.characteristics.dexterity.unpack()
                ?: error("Missing character dexterity"),
            constitution = form.characteristics.constitution.unpack()
                ?: error("Missing character constitution"),
            height = form.characteristics.height.unpack()
                ?: error("Missing character height"),
            intelligence = form.characteristics.intelligence.unpack()
                ?: error("Missing character intelligence"),
            power = form.characteristics.power.unpack()
                ?: error("Missing character power"),
            charisma = form.characteristics.charisma.unpack()
                ?: error("Missing character charisma"),
            alterations = sheet?.alterations ?: emptyList(),
            damage = sheet?.damage ?: 0,
            fatigue = sheet?.fatigue ?: 0,
            diminished = sheet?.diminished ?: 0,
            commonSkills = form.commonSkills.map { editedSkill ->
                val skillId: String = editedSkill.id.unpack()
                    ?: error("Missing skill id")
                CharacterSheet.Skill(
                    id = skillId,
                    label = editedSkill.label.unpack()
                        ?: error("Missing label for skill: $skillId"),
                    base = commonSkillBase(skillId = skillId)
                        ?: error("Missing base for skill: $skillId"),
                    description = commonSkillDescription(skillId = skillId)
                        ?: error("Missing description for skill: $skillId"),
                    bonus = editedSkill.bonus.unpack(),
                    level = editedSkill.level.unpack() ?: 1,
                    occupation = editedSkill.occupation.checked.value,
                    used = editedSkill.used,
                )
            },
            specialSkills = form.specialSkills.map { editedSkill ->
                val skillId: String = editedSkill.id.unpack()
                    ?: error("Missing skill id")
                CharacterSheet.Skill(
                    id = skillId,
                    label = editedSkill.label.unpack()
                        ?: error("Missing label for skill: $skillId"),
                    base = editedSkill.base.unpack() ?: "0",
                    description = editedSkill.description?.unpack(),
                    bonus = editedSkill.bonus.unpack(),
                    level = editedSkill.level.unpack() ?: 1,
                    occupation = editedSkill.occupation.checked.value,
                    used = editedSkill.used,
                )
            },
            magicSkills = form.magicSkills.map { editedSkill ->
                val skillId: String = editedSkill.id.unpack()
                    ?: error("Missing skill id")

                CharacterSheet.Skill(
                    id = skillId,
                    label = editedSkill.label.unpack()
                        ?: error("Missing label for skill: $skillId"),
                    base = editedSkill.base.unpack() ?: "0",
                    description = editedSkill.description?.unpack(),
                    bonus = editedSkill.bonus.unpack(),
                    level = editedSkill.level.unpack() ?: 1,
                    occupation = editedSkill.occupation.checked.value,
                    used = editedSkill.used,
                )
            },
            actions = form.actions.map {
                val actionId: String = it.id.unpack()
                    ?: error("Missing actions id")
                CharacterSheet.Roll(
                    id = actionId,
                    label = it.label.unpack()
                        ?: error("Missing label for action: $actionId"),
                    description = it.description.unpack(),
                    canBeCritical = it.canBeCritical.checked.value,
                    default = it.default.unpack()
                        ?: error("Missing default roll for action: $actionId"),
                    special = it.special?.unpack()
                        ?: if (it.canBeCritical.checked.value) error("Missing special roll for action: $actionId") else null,
                    critical = it.critical?.unpack()
                        ?: if (it.canBeCritical.checked.value) error("Missing critical roll for action: $actionId") else null,
                )
            },
            tags = form.tags.value.mapNotNull {
                if (it.highlight) it.id else null
            },
        )
    }

    suspend fun createForm(
        scope: CoroutineScope,
        sheet: CharacterSheet?,
        tags: Collection<Tag>,
    ): GMCharacterEditPageUio {
        val tagFlow = MutableStateFlow(
            tagFactory.convertToGMTagItemUio(
                tags = tags,
                selectedTagIds = sheet?.tags ?: emptyList(),
            )
        )
        val characteristics = GMCharacterEditPageUio.CharacteristicsUio(
            strength = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__str),
                value = sheet?.strength?.toString() ?: "",
            ).createLwaTextField(
                checkForError = { it.toIntOrNull() == null },
            ),
            dexterity = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__dex),
                value = sheet?.dexterity?.toString() ?: "",
            ).createLwaTextField(
                checkForError = { it.toIntOrNull() == null },
            ),
            constitution = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__con),
                value = sheet?.constitution?.toString() ?: "",
            ).createLwaTextField(
                checkForError = { it.toIntOrNull() == null },
            ),
            height = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__hei),
                value = sheet?.height?.toString() ?: "",
            ).createLwaTextField(
                checkForError = { it.toIntOrNull() == null },
            ),
            intelligence = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__int),
                value = sheet?.intelligence?.toString() ?: "",
            ).createLwaTextField(
                checkForError = { it.toIntOrNull() == null },
            ),
            power = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__pow),
                value = sheet?.power?.toString() ?: "",
            ).createLwaTextField(
                checkForError = { it.toIntOrNull() == null },
            ),
            charisma = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__cha),
                value = sheet?.charisma?.toString() ?: "",
            ).createLwaTextField(
                checkForError = { it.toIntOrNull() == null },
            ),
        )
        return GMCharacterEditPageUio(
            characterSheetId = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__id_label),
                value = sheet?.id ?: "",
            ).createLwaTextField(
                enable = sheet == null,
                checkForError = { it.isBlank() },
            ),
            name = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__name_label),
                value = sheet?.name ?: "",
            ).createLwaTextField(
                checkForError = { it.isBlank() },
            ),
            job = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__job),
                value = sheet?.job ?: "",
            ).createLwaTextField(),
            portrait = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__portrait),
                value = sheet?.portrait ?: "",
            ).createLwaTextField(),
            thumbnail = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__thumbnail),
                value = sheet?.thumbnail ?: "",
            ).createLwaTextField(),
            externalLink = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__external_link),
                value = sheet?.externalLink ?: "",
            ).createLwaTextField(),
            level = createLwaTextFieldFlow(
                label = getString(Res.string.character_sheet_edit__characteristics__level),
                value = sheet?.level?.toString() ?: "",
            ).createLwaTextField(
                checkForError = { it.toIntOrNull() == null },
            ),
            levelUp = MutableStateFlow(sheet?.shouldLevelUp ?: false).let { flow ->
                LwaCheckBoxUio(
                    enable = false,
                    checked = flow,
                    onCheckedChange = { flow.value = it },
                )
            },
            characteristics = characteristics,
            tags = tagFlow,
            commonSkills = (sheet?.commonSkills ?: commonSkills()).map {
                createCommonSkill(
                    scope = scope,
                    skill = it,
                    characteristics = characteristics
                )
            },
            specialSkills = sheet?.specialSkills?.map { createSkill(skill = it) } ?: emptyList(),
            magicSkills = sheet?.magicSkills?.map { createSkill(skill = it) } ?: emptyList(),
            actions = sheet?.actions?.map { createAction(action = it) } ?: emptyList())
    }

    private suspend fun createCommonSkill(
        scope: CoroutineScope,
        skill: CharacterSheet.Skill,
        characteristics: GMCharacterEditPageUio.CharacteristicsUio,
    ): GMSkillFieldUio {
        val baseLabel = getString(Res.string.character_sheet_edit__skills__base_label)
        val idFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__skills__id_label),
            value = skill.id,
        )
        val labelFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__skills__name_label),
            value = commonSkillLabel(skillId = skill.id) ?: "",
        )
        val baseFlow = createLwaTextFieldFlow(
            labelFlow = MutableStateFlow(
                when (skill.occupation) {
                    true -> "$baseLabel *"
                    else -> baseLabel
                }
            ),
            valueFlow = commonSkillBaseFlow(
                scope = scope,
                characteristics = characteristics,
                skillId = skill.id,
            ),
        )
        val bonusFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__skills__bonus_label),
            value = skill.bonus ?: "",
        )
        val levelFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__skills__level_label),
            value = skill.level.toString(),
        )
        return GMSkillFieldUio(
            key = "${UUID.randomUUID()}-${System.currentTimeMillis()}",
            id = idFlow.createLwaTextField(
                enable = false,
            ),
            label = labelFlow.createLwaTextField(
                enable = false,
            ),
            base = baseFlow.createLwaTextField(
                enable = false,
            ),
            description = null,
            bonus = bonusFlow.createLwaTextField(
                checkForError = { it.isNotBlank() && it.toIntOrNull() == null },
            ),
            level = levelFlow.createLwaTextField(
                checkForError = {
                    val value = it.toIntOrNull()
                    value == null || value < 1
                },
            ),
            occupation = MutableStateFlow(skill.occupation).let { flow ->
                LwaCheckBoxUio(
                    enable = true,
                    checked = flow,
                    onCheckedChange = {
                        baseFlow.labelFlow.value = when (it) {
                            true -> "$baseLabel *"
                            else -> baseLabel
                        }
                        flow.value = it
                    },
                )
            },
            used = skill.used,
        )
    }

    suspend fun createSkill(
        skill: CharacterSheet.Skill?,
    ): GMSkillFieldUio {
        val baseLabel = getString(Res.string.character_sheet_edit__skills__base_label)
        val idFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__skills__id_label),
            value = skill?.id ?: "",
        )
        val labelFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__skills__name_label),
            value = skill?.label ?: "",
        )
        val baseFlow = createLwaTextFieldFlow(
            label = when (skill?.occupation) {
                true -> "$baseLabel *"
                else -> baseLabel
            },
            value = skill?.base ?: "",
        )
        val descriptionFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__skills__description_label),
            value = skill?.description ?: "",
        )
        val bonusFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__skills__bonus_label),
            value = skill?.bonus ?: "",
        )
        val levelFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__skills__level_label),
            value = skill?.level.toString(),
        )
        val occupationFlow = MutableStateFlow(skill?.occupation ?: false)
        return GMSkillFieldUio(
            key = "${UUID.randomUUID()}-${System.currentTimeMillis()}",
            id = idFlow.createLwaTextField(
                checkForError = { it.isBlank() },
            ),
            label = labelFlow.createLwaTextField(
                checkForError = { it.isBlank() },
            ),
            base = baseFlow.createLwaTextField(
                checkForError = { it.toIntOrNull() == null },
            ),
            description = descriptionFlow.createLwaTextField(),
            bonus = bonusFlow.createLwaTextField(
                checkForError = { it.isNotBlank() && it.toIntOrNull() == null },
            ),
            level = levelFlow.createLwaTextField(
                checkForError = {
                    val value = it.toIntOrNull()
                    value == null || value < 1
                },
            ),
            occupation = LwaCheckBoxUio(
                enable = true,
                checked = occupationFlow,
                onCheckedChange = {
                    baseFlow.labelFlow.value = when (it) {
                        true -> "$baseLabel *"
                        else -> baseLabel
                    }
                    occupationFlow.value = it
                },
            ),
            used = skill?.used ?: false
        )
    }

    suspend fun createAction(
        action: CharacterSheet.Roll?,
    ): GMActionFieldUio {
        val idFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__actions__id_label),
            value = action?.id ?: "",
        )
        val labelFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__actions__name_label),
            value = action?.label ?: "",
        )
        val descriptionFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__actions__description_label),
            value = action?.description ?: "",
        )
        val defaultFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__actions__default_action_label),
            value = action?.default ?: "",
        )
        val specialFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__actions__spacial_action_label),
            value = action?.special ?: "",
        )
        val criticalFlow = createLwaTextFieldFlow(
            label = getString(Res.string.character_sheet_edit__actions__critical_action_label),
            value = action?.critical ?: "",
        )
        val canBeCriticalFlow = MutableStateFlow(action?.canBeCritical ?: false)
        return GMActionFieldUio(
            id = idFlow.createLwaTextField(
                checkForError = { it.isBlank() },
            ),
            label = labelFlow.createLwaTextField(
                checkForError = { it.isBlank() },
            ),
            description = descriptionFlow.createLwaTextField(),
            canBeCritical = LwaCheckBoxUio(
                enable = true,
                checked = canBeCriticalFlow,
                onCheckedChange = { canBeCriticalFlow.value = it },
            ),
            default = defaultFlow.createLwaTextField(
                checkForError = { it.isBlank() },
            ),
            special = specialFlow.createLwaTextField(
                checkForError = { canBeCriticalFlow.value && it.isBlank() },
            ),
            critical = criticalFlow.createLwaTextField(
                checkForError = { canBeCriticalFlow.value && it.isBlank() },
            ),
        )
    }

    private suspend fun commonSkills(): List<CharacterSheet.Skill> {
        return listOf(
            COMBAT_ID,
            DODGE_ID,
            GRAB_ID,
            THROW_ID,
            ATHLETICS_ID,
            ACROBATICS_ID,
            PERCEPTION_ID,
            SEARCH_ID,
            EMPATHY_ID,
            PERSUASION_ID,
            INTIMIDATION_ID,
            SPIEL_ID,
            BARGAIN_ID,
            DISCRETION_ID,
            SLEIGHT_OF_HAND_ID,
            AID_ID,
        ).map { id ->
            CharacterSheet.Skill(
                id = id,
                label = commonSkillLabel(id)!!,
                description = commonSkillDescription(id)!!,
                base = commonSkillBase(id)!!,
                bonus = null,
                level = 1,
                occupation = false,
                used = false,
            )
        }
    }

    private suspend fun commonSkillLabel(
        skillId: String,
    ): String? {
        return when (skillId) {
            COMBAT_ID -> Res.string.character_sheet_edit__skills__combat_label
            DODGE_ID -> Res.string.character_sheet_edit__skills__dodge_label
            GRAB_ID -> Res.string.character_sheet_edit__skills__grab_label
            THROW_ID -> Res.string.character_sheet_edit__skills__throw_label
            ATHLETICS_ID -> Res.string.character_sheet_edit__skills__athletics_label
            ACROBATICS_ID -> Res.string.character_sheet_edit__skills__acrobatics_label
            PERCEPTION_ID -> Res.string.character_sheet_edit__skills__perception_label
            SEARCH_ID -> Res.string.character_sheet_edit__skills__search_label
            EMPATHY_ID -> Res.string.character_sheet_edit__skills__empathy_label
            PERSUASION_ID -> Res.string.character_sheet_edit__skills__persuasion_label
            INTIMIDATION_ID -> Res.string.character_sheet_edit__skills__intimidation_label
            SPIEL_ID -> Res.string.character_sheet_edit__skills__spiel_label
            BARGAIN_ID -> Res.string.character_sheet_edit__skills__bargain_label
            DISCRETION_ID -> Res.string.character_sheet_edit__skills__discretion_label
            SLEIGHT_OF_HAND_ID -> Res.string.character_sheet_edit__skills__sleight_of_hand_label
            AID_ID -> Res.string.character_sheet_edit__skills__aid_label
            else -> null
        }?.let {
            getString(it)
        }
    }

    private suspend fun commonSkillDescription(
        skillId: String,
    ): String? {
        return when (skillId) {
            COMBAT_ID -> Res.string.character_sheet_edit__skills__combat_description
            DODGE_ID -> Res.string.character_sheet_edit__skills__dodge_description
            GRAB_ID -> Res.string.character_sheet_edit__skills__grab_description
            THROW_ID -> Res.string.character_sheet_edit__skills__throw_description
            ATHLETICS_ID -> Res.string.character_sheet_edit__skills__athletics_description
            ACROBATICS_ID -> Res.string.character_sheet_edit__skills__acrobatics_description
            PERCEPTION_ID -> Res.string.character_sheet_edit__skills__perception_description
            SEARCH_ID -> Res.string.character_sheet_edit__skills__search_description
            EMPATHY_ID -> Res.string.character_sheet_edit__skills__empathy_description
            PERSUASION_ID -> Res.string.character_sheet_edit__skills__persuasion_description
            INTIMIDATION_ID -> Res.string.character_sheet_edit__skills__intimidation_description
            SPIEL_ID -> Res.string.character_sheet_edit__skills__spiel_description
            BARGAIN_ID -> Res.string.character_sheet_edit__skills__bargain_description
            DISCRETION_ID -> Res.string.character_sheet_edit__skills__discretion_description
            SLEIGHT_OF_HAND_ID -> Res.string.character_sheet_edit__skills__sleight_of_hand_description
            AID_ID -> Res.string.character_sheet_edit__skills__aid_description
            else -> null
        }?.let {
            getString(it)
        }
    }

    private suspend fun commonSkillBase(
        skillId: String,
    ): String? {
        return when (skillId) {
            COMBAT_ID -> Res.string.character_sheet_edit__skills__combat_base
            DODGE_ID -> Res.string.character_sheet_edit__skills__dodge_base
            GRAB_ID -> Res.string.character_sheet_edit__skills__grab_base
            THROW_ID -> Res.string.character_sheet_edit__skills__throw_base
            ATHLETICS_ID -> Res.string.character_sheet_edit__skills__athletics_base
            ACROBATICS_ID -> Res.string.character_sheet_edit__skills__acrobatics_base
            PERCEPTION_ID -> Res.string.character_sheet_edit__skills__perception_base
            SEARCH_ID -> Res.string.character_sheet_edit__skills__search_base
            EMPATHY_ID -> Res.string.character_sheet_edit__skills__empathy_base
            PERSUASION_ID -> Res.string.character_sheet_edit__skills__persuasion_base
            INTIMIDATION_ID -> Res.string.character_sheet_edit__skills__intimidation_base
            SPIEL_ID -> Res.string.character_sheet_edit__skills__spiel_base
            BARGAIN_ID -> Res.string.character_sheet_edit__skills__bargain_base
            DISCRETION_ID -> Res.string.character_sheet_edit__skills__discretion_base
            SLEIGHT_OF_HAND_ID -> Res.string.character_sheet_edit__skills__sleight_of_hand_base
            AID_ID -> Res.string.character_sheet_edit__skills__aid_base
            else -> null
        }?.let {
            getString(it)
        }
    }

    private fun commonSkillBaseFlow(
        scope: CoroutineScope,
        characteristics: GMCharacterEditPageUio.CharacteristicsUio,
        skillId: String,
    ): MutableStateFlow<String> {
        val flow = combine(
            characteristics.strength.valueFlow.map { it.toIntOrNull() ?: 0 },
            characteristics.dexterity.valueFlow.map { it.toIntOrNull() ?: 0 },
            characteristics.constitution.valueFlow.map { it.toIntOrNull() ?: 0 },
            characteristics.height.valueFlow.map { it.toIntOrNull() ?: 0 },
            characteristics.intelligence.valueFlow.map { it.toIntOrNull() ?: 0 },
            characteristics.power.valueFlow.map { it.toIntOrNull() ?: 0 },
            characteristics.charisma.valueFlow.map { it.toIntOrNull() ?: 0 },
        ) { (strength, dexterity, constitution, height, intelligence, power, charisma) ->
            when (skillId) {
                COMBAT_ID -> skillUseCase.combat(
                    dexterity = dexterity,
                )

                DODGE_ID -> skillUseCase.dodge(
                    dexterity = dexterity,
                )

                GRAB_ID -> skillUseCase.grab(
                    strength = strength, height = height,
                )

                THROW_ID -> skillUseCase.shoot(
                    strength = strength, dexterity = dexterity,
                )

                ATHLETICS_ID -> skillUseCase.athletics(
                    strength = strength, constitution = constitution,
                )

                ACROBATICS_ID -> skillUseCase.acrobatics(
                    dexterity = dexterity, constitution = constitution,
                )

                PERCEPTION_ID -> skillUseCase.perception(
                    intelligence = intelligence,
                )

                SEARCH_ID -> skillUseCase.search(
                    intelligence = intelligence,
                )

                EMPATHY_ID -> skillUseCase.empathy(
                    charisma = charisma, intelligence = intelligence,
                )

                PERSUASION_ID -> skillUseCase.persuasion(
                    charisma = charisma,
                )

                INTIMIDATION_ID -> skillUseCase.intimidation(
                    charisma = charisma, height = height, power = power,
                )

                SPIEL_ID -> skillUseCase.spiel(
                    charisma = charisma, intelligence = intelligence,
                )

                BARGAIN_ID -> skillUseCase.bargain(
                    charisma = charisma,
                )

                DISCRETION_ID -> skillUseCase.discretion(
                    charisma = charisma, dexterity = dexterity, height = height,
                )

                SLEIGHT_OF_HAND_ID -> skillUseCase.sleightOfHand(
                    dexterity = dexterity,
                )

                AID_ID -> skillUseCase.aid(
                    intelligence = intelligence, dexterity = dexterity,
                )

                else -> null
            }?.toString()
        }

        val state = MutableStateFlow("")
        flow.onEach { value -> state.update { value ?: "" } }
            .launchIn(scope = scope)

        return state
    }

    private operator fun <T> Array<T>.component6(): T = this[5]

    private operator fun <T> Array<T>.component7(): T = this[6]
}