package com.dowstats.service.w40k

import com.dowstats.data.dto.AreaEffect
import com.dowstats.data.entities.ArmorType
import com.dowstats.data.entities.ModifiersBase.ModifiersBaseCompanion.fillDataFromRgdTable
import com.dowstats.data.entities.ModifiersBase.ModifiersBaseCompanion.filterUseless
import com.dowstats.data.entities.deathexplosion.DeathExplosion
import com.dowstats.data.entities.deathexplosion.DeathExplosionArmorPiercing
import com.dowstats.data.entities.deathexplosion.DeathExplosionModifiers
import com.dowstats.data.entities.weapon.WeaponArmorPiercing
import com.dowstats.data.rgd.RgdData
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName
import com.dowstats.data.rgd.RgdDataUtil.getStringByName
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.math.BigDecimal
import kotlin.collections.get
import kotlin.toBigDecimal

@Service
class DeathExplosionRgdExtractService @Autowired constructor(
    private val commonParseRgdService: CommonParseRgdService,
) {

    val log = LoggerFactory.getLogger(DeathExplosionRgdExtractService::class.java)

    fun getDeathExplosions(
        entityData: List<RgdData>,
        armorTypes: Set<ArmorType>,
    ): List<DeathExplosion> {
        val rootExplosion = entityData.getRgdTableByName("death_explosion_ext")
        val globalChance = rootExplosion?.getDoubleByName("chance")

        fun getExplosionModifiers(explosionPartRoot: List<RgdData>?, deathExplosion: DeathExplosion): List<DeathExplosionModifiers> =
            explosionPartRoot
                ?.getRgdTableByName("area_effect")
                ?.getRgdTableByName("weapon_damage")
                ?.getRgdTableByName("modifiers")
                ?.mapNotNull { m ->
                    if (m.name.contains("modifier_")) {
                        val mTable = m.value as List<RgdData>
                        val modifier = mTable.getRgdTableByName("modifier")
                        val maxLifetime = mTable.getDoubleByName("max_lifetime")
                        if (modifier?.getStringByName("\$REF") == "modifiers\\no_modifier.lua" || modifier == null) null else {
                            DeathExplosionModifiers().also {
                                it.deathExplosion = deathExplosion
                                it.maxLifeTime = maxLifetime
                            }.fillDataFromRgdTable(modifier)
                        }
                    } else null
                }?.filterUseless() ?: emptyList()

        fun getExplosionArmorPiercings(areaEffectData: AreaEffect, deathExplosion: DeathExplosion): List<DeathExplosionArmorPiercing> = armorTypes.map {
            val deathExplosionArmorPiercing = DeathExplosionArmorPiercing()
            deathExplosionArmorPiercing.deathExplosion = deathExplosion
            deathExplosionArmorPiercing.armorType = it
            val piercingValue =
                (areaEffectData.weaponDmgMap[it.id] ?: areaEffectData.defaultArmorPiercing).toBigDecimal()
            deathExplosionArmorPiercing.piercingValue =
                piercingValue.let { pv -> if (pv <= BigDecimal(100)) pv else BigDecimal(100) }
            deathExplosionArmorPiercing
        }

        return rootExplosion?.getRgdTableByName("death_explosions")
            ?.mapNotNull { explosion ->
                if (explosion.name.contains("death_explosion")) {
                    val explosionPartRoot = explosion.value as List<RgdData>
                    val chance = explosionPartRoot.getDoubleByName("chance")
                    val areaEffect = explosionPartRoot.getRgdTableByName("area_effect")?.let { commonParseRgdService.getAreaEffectData(it) }

                    DeathExplosion().also {
                        it.globalChance = globalChance
                        it.chance = chance
                        it.minDamage = areaEffect?.minDamage
                        it.maxDamage = areaEffect?.maxDamage
                        it.minDamageValue = areaEffect?.minDamageValue
                        it.moraleDamage = areaEffect?.moraleDamage
                        it.radius = areaEffect?.damageRadius
                        it.throwForceMin = areaEffect?.throwForceMin
                        it.throwForceMax = areaEffect?.throwForceMax
                        it.explosionModifiers += getExplosionModifiers(explosionPartRoot, it)
                        areaEffect?.let{ ae ->
                            it.explosionPiercings += getExplosionArmorPiercings(ae, it)
                        }
                    }

                } else null
            } ?: emptyList()

    }
}
