package com.dowstats.data.entities.sergant

import com.dowstats.data.dto.controllers.AffectedDataDto
import com.dowstats.data.dto.controllers.EntityCompressDtoObject.compressDto
import com.dowstats.data.dto.controllers.RequirementDto
import com.dowstats.data.dto.controllers.SergeantDto
import com.dowstats.data.dto.controllers.SergeantUnitShortDtoObject.toShortDtoSet
import com.dowstats.data.dto.controllers.WeaponSlotDto
import com.dowstats.data.dto.controllers.WeaponUnitShortDtoObject.toShortDtoSet
import com.dowstats.data.entities.ArmorType
import com.dowstats.data.entities.ability.Ability
import com.dowstats.data.entities.weapon.Weapon.HardpointPosition
import com.dowstats.data.entities.addon.BuildingAddon
import com.dowstats.data.entities.building.Building
import com.dowstats.data.entities.deathexplosion.DeathExplosion
import com.dowstats.data.entities.research.Research
import com.dowstats.data.entities.unit.DowUnit
import com.dowstats.data.entities.weapon.Weapon
import com.fasterxml.jackson.annotation.JsonIgnore
import jakarta.persistence.*


@Entity
@Table(name = "sergeants")
class Sergeant {

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

    @ManyToOne
    @JoinColumn(name = "armour_type_id", nullable = false)
    var armorType: ArmorType? = null

    @ManyToOne
    @JoinColumn(name = "armour_type_2_id")
    var armorType2: ArmorType? = null

    @ManyToOne
    @JoinColumn(name = "unit_id", nullable = false)
    @JsonIgnore
    var unit: DowUnit? = null

    var name: String? = null
    var description: String? = null
    var filename: String = ""
    var buildCostRequisition: Double? = null
    var buildCostPower: Double? = null
    var buildCostPopulation: Double? = null
    var buildCostFaith: Double? = null
    var buildCostSouls: Double? = null
    var buildCostTime: Double? = null
    var health: Int? = null
    var armour: Double? = null
    var healthRegeneration: Double? = null
    var moraleIncomeMax: Double? = null
    var moraleIncomeRate: Double? = null
    var moraleDeathPenalty: Int? = null
    var mass: Int? = null
    var upTime: Double? = null
    var sightRadius: Int? = null
    var detectRadius: Int? = null
    var icon: String? = null
    var uiHotkeyName: String? = null
    var faithIncome: Double? = null
    var powerIncome: Double? = null
    var requisitionIncome: Double? = null
    var mobValue: Double? = null

    var modId: Long? = null

    @Transient
    var weaponHardpoints: MutableSet<HardpointPosition> = mutableSetOf()

    @OneToMany(mappedBy = "sergeant", cascade = [CascadeType.ALL])
    var weapons: MutableSet<SergeantWeapon>? = null

    @OneToMany(cascade = [CascadeType.ALL])
    @JoinTable(name = "sergeant_death_explosion",
        joinColumns = [JoinColumn(name = "sergeant_id")],
        inverseJoinColumns = [JoinColumn(name = "death_explosion_id")])
    var deathExplosions: MutableSet<DeathExplosion> = mutableSetOf()

    @ManyToMany
    @JoinTable(name = "sergeant_abilities",
        joinColumns = [JoinColumn(name = "sergeant_id")],
        inverseJoinColumns = [JoinColumn(name = "ability_id")])
    var abilities: MutableSet<Ability> = mutableSetOf()

    @ManyToMany
    @JoinTable(name = "researches_affected_sergeants",
        joinColumns = [JoinColumn(name = "sergeant_id")],
        inverseJoinColumns = [JoinColumn(name = "research_id")])
    var affectedResearches: MutableSet<Research> = mutableSetOf()

    @ManyToMany
    @JoinTable(name = "addon_affected_sergeants",
        joinColumns = [JoinColumn(name = "sergeant_id")],
        inverseJoinColumns = [JoinColumn(name = "addon_id")])
    var affectedAddons: MutableSet<BuildingAddon> = mutableSetOf()

    @ManyToMany
    @JoinTable(name = "building_affected_sergeants",
        joinColumns = [JoinColumn(name = "sergeant_id")],
        inverseJoinColumns = [JoinColumn(name = "building_id")])
    var affectedBuildings: MutableSet<Building> = mutableSetOf()

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

    @ManyToMany
    @JoinTable(name = "sergeant_affected_sergeants",
        joinColumns = [JoinColumn(name = "sergeant_id_affected")],
        inverseJoinColumns = [JoinColumn(name = "sergeant_id")])
    var affectedSergeants: MutableSet<Sergeant> = mutableSetOf()

    @ManyToMany
    @JoinTable(name = "units_affected_sergeants",
        joinColumns = [JoinColumn(name = "sergeant_id")],
        inverseJoinColumns = [JoinColumn(name = "unit_id")])
    var affectedUnits: MutableSet<DowUnit> = mutableSetOf()

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

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

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

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


    @OneToMany(mappedBy = "sergeant", cascade = [CascadeType.ALL])
    var sergeantModifiers: MutableSet<SergeantModifiers> = mutableSetOf()

    @OneToMany(mappedBy = "sergeant", cascade = [CascadeType.ALL])
    var sergeantRequirements: MutableSet<SergeantRequirements> = mutableSetOf()

    fun toDto(weapons: Set<WeaponSlotDto>, requirements: RequirementDto?,): SergeantDto =
        SergeantDto(
            id!!,
            armorType?.toDto(),
            armorType2?.toDto(),
            name,
            description,
            filename!!,
            buildCostRequisition,
            buildCostPower,
            buildCostPopulation,
            buildCostFaith,
            buildCostSouls,
            buildCostTime,
            faithIncome,
            powerIncome,
            requisitionIncome,
            mobValue,
            health,
            armour,
            healthRegeneration,
            moraleDeathPenalty,
            moraleIncomeMax,
            moraleIncomeRate,
            mass,
            upTime,
            sightRadius,
            detectRadius,
            icon,
            deathExplosions.map { it.toDto(modId!!) }.toSet(),
            weapons.toList(),
            abilities.sortedWith ( compareBy<Ability> { it.activation?.id }.thenBy{ it.uiIndexHint.let { 0 - it } }.thenBy{ it.name}).map { it.toShortDto() }.toSet(),
            affectedResearches.map { it.toResearchShortDto() }.toSet(),
            sergeantModifiers.map { it.toDto() }.sortedBy { it.target },
            AffectedDataDto(
                affectedOnUnits.map { it.compressDto() }.toSet(),
                affectedOnSergeants.toShortDtoSet(),
                affectedOnBuildings.map { it.compressDto() }.toSet(),
                affectedOnWeapons.toShortDtoSet(),
            ),
            requirements,
            uiHotkeyName,
        )
}
