package com.pixelized.desktop.lwa.ui.screen.levelup

import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipUio
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction
import com.pixelized.desktop.lwa.ui.overlay.roll.RollResult
import com.pixelized.desktop.lwa.ui.overlay.roll.RollResult.BoundedRollResult.Result
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpCharacteristicUio
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpSkillUio
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpSubCharacteristicUio
import com.pixelized.shared.lwa.model.AlteredCharacterSheet
import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
import com.pixelized.shared.lwa.model.alteration.Alteration
import com.pixelized.shared.lwa.model.alteration.FieldAlteration
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.parser.expression.Expression
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
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.character_sheet__sub_characteristics__damage_bonus
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hit_point
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hp_grow
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__learning
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__power_point
import lwacharactersheet.composeapp.generated.resources.ic_cognition_24dp
import lwacharactersheet.composeapp.generated.resources.ic_heart_24dp
import lwacharactersheet.composeapp.generated.resources.ic_heart_plus_24dp
import lwacharactersheet.composeapp.generated.resources.ic_swords_24dp
import lwacharactersheet.composeapp.generated.resources.ic_water_drop_24dp
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 lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__bonus_damage
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hit_point
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hp_grow
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__learning
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__power_point
import org.jetbrains.compose.resources.getString

class LevelUpFactory(
    private val alteredCharacterSheetFactory: AlteredCharacterSheetFactory,
    private val expressionUseCase: ExpressionUseCase,
) {

    suspend fun convertToLevelUpHeaderUio(
        characterSheet: CharacterSheet?,
        selectedCharacteristicId: String?,
    ): LevelUpHeaderUio? {
        if (characterSheet == null) return null

        val levelAlteration = FieldAlteration(
            alterationId = CharacterSheet.CharacteristicId.LVL,
            metadata = Alteration.MetaData(
                name = "LevelUp-${CharacterSheet.CharacteristicId.LVL}",
                description = "Fake alteration for a levelUp simulation. Alter the ${CharacterSheet.CharacteristicId.LVL} stat.",
                icon = null,
            ),
            expression = Expression.Flat(1),
        )

        val alteredCharacterSheet = alteredCharacterSheetFactory.sheet(
            characterSheet = characterSheet,
            alterations = emptyMap(),
        )
        val levelUpCharacterSheet = alteredCharacterSheetFactory.sheet(
            characterSheet = characterSheet,
            alterations = selectedCharacteristicId
                ?.let {
                    val characteristic = FieldAlteration(
                        alterationId = it,
                        metadata = Alteration.MetaData(
                            name = "LevelUp-$it",
                            description = "Fake alteration for a levelUp simulation. Alter the $it stat.",
                            icon = null,
                        ),
                        expression = Expression.Flat(1),
                    )
                    mapOf(
                        CharacterSheet.CharacteristicId.LVL to listOf(levelAlteration),
                        it to listOf(characteristic),
                    )
                }
                ?: mapOf(
                    CharacterSheet.CharacteristicId.LVL to listOf(levelAlteration),
                ),
        )

        return LevelUpHeaderUio(
            name = characterSheet.name,
            portrait = characterSheet.portrait,
            level = characterSheet.level,
            hp = LevelUpSubCharacteristicUio(
                icon = Res.drawable.ic_heart_24dp,
                base = "${alteredCharacterSheet.maxHp}",
                levelUp = "${levelUpCharacterSheet.maxHp}",
                tooltip = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__sub_characteristics__hit_point),
                    description = getString(Res.string.tooltip__sub_characteristics__hit_point)
                ),
            ),
            pp = LevelUpSubCharacteristicUio(
                icon = Res.drawable.ic_water_drop_24dp,
                base = "${alteredCharacterSheet.maxPp}",
                levelUp = "${levelUpCharacterSheet.maxPp}",
                tooltip = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__sub_characteristics__power_point),
                    description = getString(Res.string.tooltip__sub_characteristics__power_point)
                )
            ),
            bonus = LevelUpSubCharacteristicUio(
                icon = Res.drawable.ic_swords_24dp,
                base = alteredCharacterSheet.damageBonus,
                levelUp = levelUpCharacterSheet.damageBonus,
                tooltip = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__sub_characteristics__damage_bonus),
                    description = getString(Res.string.tooltip__sub_characteristics__bonus_damage)
                ),
            ),
            grow = LevelUpSubCharacteristicUio(
                icon = Res.drawable.ic_heart_plus_24dp,
                base = "${alteredCharacterSheet.hpGrow}",
                levelUp = "${levelUpCharacterSheet.hpGrow}",
                tooltip = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__sub_characteristics__hp_grow),
                    description = getString(Res.string.tooltip__sub_characteristics__hp_grow)
                ),
            ),
            learn = LevelUpSubCharacteristicUio(
                icon = Res.drawable.ic_cognition_24dp,
                base = "${alteredCharacterSheet.learning}",
                levelUp = "${levelUpCharacterSheet.learning}",
                tooltip = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__sub_characteristics__learning),
                    description = getString(Res.string.tooltip__sub_characteristics__learning)
                ),
            )
        )
    }

    suspend fun convertToLevelUpCharacteristicUio(
        characterSheet: CharacterSheet?,
        selectedCharacteristicId: String?,
    ): List<LevelUpCharacteristicUio> {
        if (characterSheet == null) return emptyList()

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

        return listOf(
            LevelUpCharacteristicUio(
                characteristicId = CharacterSheet.CharacteristicId.STR,
                label = getString(Res.string.character_sheet__characteristics__str),
                value = alteredCharacterSheet.strength,
                selected = selectedCharacteristicId == CharacterSheet.CharacteristicId.STR,
                tooltips = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__characteristics__str),
                    description = getString(Res.string.tooltip__characteristics__strength),
                ),
            ),
            LevelUpCharacteristicUio(
                characteristicId = CharacterSheet.CharacteristicId.DEX,
                label = getString(Res.string.character_sheet__characteristics__dex),
                value = alteredCharacterSheet.dexterity,
                selected = selectedCharacteristicId == CharacterSheet.CharacteristicId.DEX,
                tooltips = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__characteristics__dex),
                    description = getString(Res.string.tooltip__characteristics__dexterity),
                ),
            ),
            LevelUpCharacteristicUio(
                characteristicId = CharacterSheet.CharacteristicId.CON,
                label = getString(Res.string.character_sheet__characteristics__con),
                value = alteredCharacterSheet.constitution,
                selected = selectedCharacteristicId == CharacterSheet.CharacteristicId.CON,
                tooltips = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__characteristics__con),
                    description = getString(Res.string.tooltip__characteristics__constitution),
                ),
            ),
            LevelUpCharacteristicUio(
                characteristicId = CharacterSheet.CharacteristicId.HEI,
                label = getString(Res.string.character_sheet__characteristics__hei),
                value = alteredCharacterSheet.height,
                selected = selectedCharacteristicId == CharacterSheet.CharacteristicId.HEI,
                tooltips = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__characteristics__hei),
                    description = getString(Res.string.tooltip__characteristics__height),
                ),
            ),
            LevelUpCharacteristicUio(
                characteristicId = CharacterSheet.CharacteristicId.INT,
                label = getString(Res.string.character_sheet__characteristics__int),
                value = alteredCharacterSheet.intelligence,
                selected = selectedCharacteristicId == CharacterSheet.CharacteristicId.INT,
                tooltips = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__characteristics__int),
                    description = getString(Res.string.tooltip__characteristics__intelligence),
                ),
            ),
            LevelUpCharacteristicUio(
                characteristicId = CharacterSheet.CharacteristicId.POW,
                label = getString(Res.string.character_sheet__characteristics__pow),
                value = alteredCharacterSheet.power,
                selected = selectedCharacteristicId == CharacterSheet.CharacteristicId.POW,
                tooltips = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__characteristics__pow),
                    description = getString(Res.string.tooltip__characteristics__power),
                ),
            ),
            LevelUpCharacteristicUio(
                characteristicId = CharacterSheet.CharacteristicId.CHA,
                label = getString(Res.string.character_sheet__characteristics__cha),
                value = alteredCharacterSheet.charisma,
                selected = selectedCharacteristicId == CharacterSheet.CharacteristicId.CHA,
                tooltips = BasicTooltipUio(
                    title = getString(Res.string.character_sheet__characteristics__cha),
                    description = getString(Res.string.tooltip__characteristics__charisma),
                ),
            ),
        )
    }

    fun convertToLevelUpSectionUio(
        characterSheetId: String,
        characterSheet: CharacterSheet?,
        results: Map<String, RollResult.BoundedRollResult>,
    ): LevelUpSectionUio? {
        if (characterSheet == null) return null

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

        val commonSkills = characterSheet.commonSkills.mapNotNull { skill ->
            levelUpSkillUio(
                characterSheetId = characterSheetId,
                alteredCharacterSheet = alteredCharacterSheet,
                skill = skill,
                results = results,
            )
        }.takeIf {
            it.isNotEmpty()
        }

        val specialSkills = characterSheet.specialSkills.mapNotNull { skill ->
            levelUpSkillUio(
                characterSheetId = characterSheetId,
                alteredCharacterSheet = alteredCharacterSheet,
                skill = skill,
                results = results,
            )
        }.takeIf {
            it.isNotEmpty()
        }

        val magicSkills = characterSheet.magicSkills.mapNotNull { skill ->
            levelUpSkillUio(
                characterSheetId = characterSheetId,
                alteredCharacterSheet = alteredCharacterSheet,
                skill = skill,
                results = results,
            )
        }.takeIf {
            it.isNotEmpty()
        }

        return LevelUpSectionUio(
            commonSkills = commonSkills,
            specialSkills = specialSkills,
            magicSkills = magicSkills,
        )
    }

    private fun levelUpSkillUio(
        characterSheetId: String,
        alteredCharacterSheet: AlteredCharacterSheet,
        skill: CharacterSheet.Skill,
        results: Map<String, RollResult.BoundedRollResult>,
    ): LevelUpSkillUio? {
        if (!skill.used) return null

        val value = expressionUseCase.computeSkillValue(
            sheet = alteredCharacterSheet,
            skill = skill,
            diminished = 0,
            alterations = emptyMap(),
        )

        val success = (100 - value + alteredCharacterSheet.learning).coerceIn(1, 100)

        return LevelUpSkillUio(
            skillId = skill.id,
            label = skill.label,
            value = value,
            level = skill.level,
            levelUp = results.isSkillLeveledUp(skillId = skill.id),
            occupation = skill.occupation,
            tooltips = skill.description?.let {
                BasicTooltipUio(
                    title = skill.label,
                    description = it,
                )
            },
            roll = when (results[skill.id]) {
                null -> RollAction.Uio.BoundedRollActionUio(
                    characterSheetId = characterSheetId,
                    label = skill.label,
                    rollAction = "1d100",
                    rollSuccessValue = success,
                )

                else -> null
            },
        )
    }
}

fun Map<String, RollResult.BoundedRollResult>.isSkillLeveledUp(skillId: String): Boolean {
    return this[skillId]?.let { roll ->
        roll.result == Result.CriticalSuccess || roll.result == Result.SpecialSuccess || roll.result == Result.Success
    } ?: false
}