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

import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipUio
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.item.CharacterDetailSheetActionUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.item.CharacterDetailSheetCharacteristicUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.item.CharacterDetailSheetSkillUio
import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
import com.pixelized.shared.lwa.model.alteration.FieldAlteration
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__cha
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__con
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__dex
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__hei
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__int
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__pow
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__str
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__charisma
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__constitution
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__dexterity
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__height
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__intelligence
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__power
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__strength
import org.jetbrains.compose.resources.getString
import java.text.Collator

class CharacterDetailSheetFactory(
    private val alteredCharacterSheetFactory: AlteredCharacterSheetFactory,
    private val expressionUseCase: ExpressionUseCase,
    private val characterSheetRepository: CharacterSheetRepository,
    private val alterationRepository: AlterationRepository,
) {
    fun convertToCharacterDetailSheetUioFlow(
        characterSheetId: String,
        scope: CoroutineScope,
        started: SharingStarted = SharingStarted.Eagerly,
        initialValue: () -> CharacterDetailSheetUio?,
    ): StateFlow<CharacterDetailSheetUio?> {
        return combine(
            characterSheetRepository.characterDetailFlow(characterSheetId = characterSheetId),
            alterationRepository.activeFieldAlterationsFlow(characterSheetId = characterSheetId),
        ) { characterSheet, alterations ->
            convertToCharacterDetailSheetUio(
                characterSheetId = characterSheetId,
                characterSheet = characterSheet,
                alterations = alterations,
            )
        }.stateIn(
            scope = scope,
            started = started,
            initialValue = initialValue(),
        )
    }

    suspend fun convertToCharacterDetailSheetUio(
        characterSheetId: String,
        characterSheet: CharacterSheet?,
        alterations: Map<String, List<FieldAlteration>>,
    ): CharacterDetailSheetUio? {
        if (characterSheet == null) return null

        val alteredCharacterSheet = alteredCharacterSheetFactory.sheet(
            characterSheet = characterSheet,
            alterations = alterations,
        )

        return CharacterDetailSheetUio(
            characterSheetId = characterSheetId,
            characteristics = listOf(
                CharacterDetailSheetCharacteristicUio(
                    label = getString(Res.string.character_sheet__characteristics__str),
                    value = "${alteredCharacterSheet.strength}",
                    tooltips = BasicTooltipUio(
                        title = getString(Res.string.character_sheet__characteristics__str),
                        description = getString(Res.string.tooltip__characteristics__strength),
                    ),
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = getString(Res.string.character_sheet__characteristics__str),
                        rollAction = "1d100",
                        rollSuccessValue = alteredCharacterSheet.strength * 5 - alteredCharacterSheet.diminished,
                    ),
                ),
                CharacterDetailSheetCharacteristicUio(
                    label = getString(Res.string.character_sheet__characteristics__dex),
                    value = "${alteredCharacterSheet.dexterity}",
                    tooltips = BasicTooltipUio(
                        title = getString(Res.string.character_sheet__characteristics__dex),
                        description = getString(Res.string.tooltip__characteristics__dexterity),
                    ),
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = getString(Res.string.character_sheet__characteristics__dex),
                        rollAction = "1d100",
                        rollSuccessValue = alteredCharacterSheet.dexterity * 5 - alteredCharacterSheet.diminished,
                    ),
                ),
                CharacterDetailSheetCharacteristicUio(
                    label = getString(Res.string.character_sheet__characteristics__con),
                    value = "${alteredCharacterSheet.constitution}",
                    tooltips = BasicTooltipUio(
                        title = getString(Res.string.character_sheet__characteristics__con),
                        description = getString(Res.string.tooltip__characteristics__constitution),
                    ),
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = getString(Res.string.character_sheet__characteristics__con),
                        rollAction = "1d100",
                        rollSuccessValue = alteredCharacterSheet.constitution * 5 - alteredCharacterSheet.diminished,
                    ),
                ),
                CharacterDetailSheetCharacteristicUio(
                    label = getString(Res.string.character_sheet__characteristics__hei),
                    value = "${alteredCharacterSheet.height}",
                    tooltips = BasicTooltipUio(
                        title = getString(Res.string.character_sheet__characteristics__hei),
                        description = getString(Res.string.tooltip__characteristics__height),
                    ),
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = getString(Res.string.character_sheet__characteristics__hei),
                        rollAction = "1d100",
                        rollSuccessValue = alteredCharacterSheet.height * 5 - alteredCharacterSheet.diminished,
                    ),
                ),
                CharacterDetailSheetCharacteristicUio(
                    label = getString(Res.string.character_sheet__characteristics__int),
                    value = "${alteredCharacterSheet.intelligence}",
                    tooltips = BasicTooltipUio(
                        title = getString(Res.string.character_sheet__characteristics__int),
                        description = getString(Res.string.tooltip__characteristics__intelligence),
                    ),
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = getString(Res.string.character_sheet__characteristics__int),
                        rollAction = "1d100",
                        rollSuccessValue = alteredCharacterSheet.intelligence * 5 - alteredCharacterSheet.diminished,
                    ),
                ),
                CharacterDetailSheetCharacteristicUio(
                    label = getString(Res.string.character_sheet__characteristics__pow),
                    value = "${alteredCharacterSheet.power}",
                    tooltips = BasicTooltipUio(
                        title = getString(Res.string.character_sheet__characteristics__pow),
                        description = getString(Res.string.tooltip__characteristics__power),
                    ),
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = getString(Res.string.character_sheet__characteristics__pow),
                        rollAction = "1d100",
                        rollSuccessValue = alteredCharacterSheet.power * 5 - alteredCharacterSheet.diminished,
                    ),
                ),
                CharacterDetailSheetCharacteristicUio(
                    label = getString(Res.string.character_sheet__characteristics__cha),
                    value = "${alteredCharacterSheet.charisma}",
                    tooltips = BasicTooltipUio(
                        title = getString(Res.string.character_sheet__characteristics__cha),
                        description = getString(Res.string.tooltip__characteristics__charisma),
                    ),
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = getString(Res.string.character_sheet__characteristics__cha),
                        rollAction = "1d100",
                        rollSuccessValue = alteredCharacterSheet.charisma * 5 - alteredCharacterSheet.diminished,
                    ),
                ),
            ),
            commonSkills = characterSheet.commonSkills.map { skill ->
                val value = expressionUseCase.computeSkillValue(
                    sheet = alteredCharacterSheet,
                    skill = skill,
                    diminished = alteredCharacterSheet.diminished,
                    alterations = alterations,
                )
                CharacterDetailSheetSkillUio(
                    skillId = skill.id,
                    label = skill.label,
                    value = "$value",
                    used = skill.used,
                    occupation = skill.occupation,
                    tooltips = skill.description?.let {
                        BasicTooltipUio(
                            title = skill.label,
                            description = it,
                        )
                    },
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = skill.label,
                        rollAction = "1d100",
                        rollSuccessValue = value,
                    ),
                )
            }.sortedWith(compareBy(Collator.getInstance()) { it.label }),
            characterSheet.specialSkills.map { skill ->
                val value = expressionUseCase.computeSkillValue(
                    sheet = alteredCharacterSheet,
                    skill = skill,
                    diminished = alteredCharacterSheet.diminished,
                    alterations = alterations,
                )
                CharacterDetailSheetSkillUio(
                    skillId = skill.id,
                    label = skill.label,
                    value = "$value",
                    used = skill.used,
                    occupation = skill.occupation,
                    tooltips = skill.description?.let {
                        BasicTooltipUio(
                            title = skill.label,
                            description = it,
                        )
                    },
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = skill.label,
                        rollAction = "1d100",
                        rollSuccessValue = value,
                    ),
                )
            }.sortedWith(compareBy(Collator.getInstance()) { it.label }),
            magicSkills = characterSheet.magicSkills.map { skill ->
                val value = expressionUseCase.computeSkillValue(
                    sheet = alteredCharacterSheet,
                    skill = skill,
                    diminished = alteredCharacterSheet.diminished,
                    alterations = alterations,
                )
                CharacterDetailSheetSkillUio(
                    skillId = skill.id,
                    label = skill.label,
                    value = "$value",
                    used = skill.used,
                    occupation = skill.occupation,
                    tooltips = skill.description?.let {
                        BasicTooltipUio(
                            title = skill.label,
                            description = it,
                        )
                    },
                    roll = RollAction.Uio.BoundedRollActionUio(
                        characterSheetId = characterSheetId,
                        label = skill.label,
                        rollAction = "1d100",
                        rollSuccessValue = value,
                    ),
                )
            }.sortedWith(compareBy(Collator.getInstance()) { it.label }),
            actions = characterSheet.actions.map { action ->
                CharacterDetailSheetActionUio(
                    actionId = action.id,
                    label = action.label,
                    tooltips = action.description?.let {
                        BasicTooltipUio(
                            title = action.label,
                            description = it,
                        )
                    },
                    roll = RollAction.Uio.BoundlessRollActionUio(
                        characterSheetId = characterSheetId,
                        label = action.label,
                        canBeCritical = action.canBeCritical,
                        rollDefaultAction = action.default,
                        rollSpecialAction = action.special,
                        rollCriticalAction = action.critical,
                    )
                )
            }.sortedWith(compareBy(Collator.getInstance()) { it.label }),
        )
    }
}