package com.dowstats.data.entities.ability

import com.dowstats.data.dto.controllers.AffectedDataDto
import com.dowstats.data.dto.controllers.ArmorPiercingDto
import com.dowstats.data.dto.controllers.EntityCompressDtoObject.compressDto
import com.dowstats.data.dto.controllers.RequirementDto
import com.dowstats.data.dto.controllers.SergeantUnitShortDtoObject.toShortDtoSet
import com.dowstats.data.dto.controllers.WeaponUnitShortDtoObject.toShortDtoSet
import com.dowstats.data.dto.controllers.ability.AbilityDto
import com.dowstats.data.dto.controllers.ability.AbilityEnvironmentDto
import com.dowstats.data.dto.controllers.ability.AbilityShortDto
import com.dowstats.data.entities.Activation
import com.dowstats.data.entities.AreaEffect
import com.dowstats.data.entities.AreaFilter
import com.dowstats.data.entities.ArmorType
import com.dowstats.data.entities.building.Building
import com.dowstats.data.entities.sergant.Sergeant
import com.dowstats.data.entities.unit.DowUnit
import com.dowstats.data.entities.weapon.Weapon
import jakarta.persistence.*
import java.math.BigDecimal


@Entity
@Table(name = "abilities")
class Ability {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null

    var modId: Long? = null
    var filename: String? = null
    var name: String? = null

    var description: String? = null

    var costRequisition: Double? = null
    var costPower: Double? = null
    var costFaith: Double? = null
    var costSouls: Double? = null
    var icon: String? = null

    var uiIndexHint: Int = 0
    var uiHotkeyName: String? = null
    var childAbilityName: String? = null
    var initialDelayTime: Double? = null
    var radius: Double? = null
    var minDamage: Double? = null
    var minDamageValue: Double? = null
    var maxDamage: Double? = null
    var moraleDamage: Double? = null
    var throwForceMin: Double? = null
    var throwForceMax: Double? = null

    var range: Double? = null
    var rechargeTime: Double? = null
    var rechargeTimerGlobal: Boolean? = null
    var refreshTime: Double? = null
    var durationTime: Double? = null

    var spawnedEntityName: String? = null

    @ManyToOne
    @JoinColumn(name = "activation_id")
    var activation: Activation? = null

    @ManyToOne
    @JoinColumn(name = "area_effect_id")
    var areaEffect: AreaEffect? = null

    @ManyToOne
    @JoinColumn(name = "area_filter_id")
    var areaFilter: AreaFilter? = null

    @ManyToMany
    @JoinTable(name = "unit_abilities",
        joinColumns = [JoinColumn(name = "ability_id")],
        inverseJoinColumns = [JoinColumn(name = "unit_id")])
    var unitsUse: MutableSet<DowUnit>? = null

    @OneToMany(mappedBy = "ability", cascade = [CascadeType.ALL])
    var abilityModifiers: MutableSet<AbilityModifiers> = mutableSetOf()

    @OneToMany(mappedBy = "ability", cascade = [CascadeType.ALL])
    var abilityRequirements: MutableSet<AbilityRequirements> = mutableSetOf()

    @OneToMany(mappedBy = "ability", cascade = [CascadeType.ALL])
    var abilityPiercings: MutableSet<AbilityArmorPiercing> = mutableSetOf()

    @ManyToMany
    @JoinTable(name = "ability_affected_units",
        joinColumns = [JoinColumn(name = "ability_id")],
        inverseJoinColumns = [JoinColumn(name = "unit_id")])
    var affectedOnUnits: MutableSet<DowUnit> = mutableSetOf()

    @ManyToMany
    @JoinTable(name = "ability_affected_sergeants",
        joinColumns = [JoinColumn(name = "ability_id")],
        inverseJoinColumns = [JoinColumn(name = "sergeant_id")])
    var affectedOnSergeants: MutableSet<Sergeant> = mutableSetOf()

    @ManyToMany
    @JoinTable(name = "ability_affected_buildings",
        joinColumns = [JoinColumn(name = "ability_id")],
        inverseJoinColumns = [JoinColumn(name = "building_id")])
    var affectedOnBuildings: MutableSet<Building> = mutableSetOf()

    @ManyToMany
    @JoinTable( name = "ability_affected_weapons",
        joinColumns = [JoinColumn(name = "ability_id")],
        inverseJoinColumns = [JoinColumn(name = "weapon_id")])
    var affectedOnWeapons: MutableSet<Weapon> = mutableSetOf()

    @ManyToMany
    @JoinTable(name = "ability_target_filter",
        joinColumns = [JoinColumn(name = "ability_id")],
        inverseJoinColumns = [JoinColumn(name = "armor_type_id")])
    var abilityTargetFilters: MutableSet<ArmorType> = mutableSetOf()

    fun toShortDto() = AbilityShortDto(id, name, filename, icon, uiIndexHint, activation?.name)

    fun toDto(requirements: RequirementDto?, childAbility: AbilityDto?, abilityEnvironmentDto: AbilityEnvironmentDto?): AbilityDto = AbilityDto(
        id = id,
        modId = modId,
        filename = filename,
        name = name,
        description = description,
        costRequisition = costRequisition,
        costPower = costPower,
        costFaith = costFaith,
        costSouls = costSouls,
        icon = icon,
        uiIndexHint = uiIndexHint,
        hotkey = uiHotkeyName,
        childAbility = childAbility,
        initialDelayTime = initialDelayTime,
        range = range,
        rechargeTime = rechargeTime,
        rechargeTimerGlobal = rechargeTimerGlobal,
        refreshTime = refreshTime,
        durationTime = durationTime,
        radius = radius,
        minDamage = minDamage,
        minDamageValue = minDamageValue,
        maxDamage = maxDamage,
        moraleDamage = moraleDamage,
        throwForceMin = throwForceMin,
        throwForceMax = throwForceMax,
        activation = activation?.name,
        areaEffect = areaEffect?.name,
        areaFilter = areaFilter?.name,
        modifiers = abilityModifiers.map { it.toDto().copy(maxLifeTime = it.maxLifeTime) }.sortedBy { it.target },
        requirements = requirements,
        affectedData = AffectedDataDto(
            affectedOnUnits.map { it.compressDto() }.toSet(),
            affectedOnSergeants.toShortDtoSet(),
            affectedOnBuildings.map { it.compressDto() }.toSet(),
            affectedOnWeapons.toShortDtoSet(),
        ),
        targetFilter = abilityTargetFilters.map { it.toDto() },
        piercings = abilityPiercings.map { ArmorPiercingDto(it.armorType?.toDto(), it.piercingValue ?: BigDecimal.ZERO) },
        abilityEnvironmentDto,
    )

}
