package com.dowstats.data.entities.building

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.SergeantUnitShortDtoObject.toShortDtoSet
import com.dowstats.data.dto.controllers.WeaponSlotDto
import com.dowstats.data.dto.controllers.WeaponUnitShortDtoObject.toShortDtoSet
import com.dowstats.data.dto.controllers.building.BuildingAddonDto
import com.dowstats.data.dto.controllers.building.BuildingFullDto
import com.dowstats.data.dto.controllers.research.ResearchShortDto
import com.dowstats.data.entities.ArmorType
import com.dowstats.data.entities.unit.DowUnit
import com.dowstats.data.entities.unit.DowUnitObject.toUnitDto
import com.dowstats.data.entities.Race
import com.dowstats.data.entities.ability.Ability
import com.dowstats.data.entities.sergant.Sergeant
import com.dowstats.data.entities.weapon.Weapon
import com.dowstats.data.entities.weapon.Weapon.HardpointPosition
import com.dowstats.data.entities.addon.BuildingAddon
import com.dowstats.data.entities.deathexplosion.DeathExplosion
import com.dowstats.data.entities.research.Research
import jakarta.persistence.*


@Entity
@Table(name = "buildings")
class Building {

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

    var canBuild: Boolean? = true

    @ManyToOne
    @JoinColumn(name = "race_id", nullable = false)
    var race: Race? = null

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

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

    var name: String? = null
    var description: String? = null
    var filename: String? = null
    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 sightRadius: Int? = null
    var detectRadius: Int? = null
    var repairMax: Int? = null
    var uiIndexHint: Int = 0
    var uiHotkeyName: String? = null
    var advancedBuildOption: Boolean = false
    var icon: String? = null
    var modId: Long? = null
    var faithIncome: Double? = null
    var powerIncome: Double? = null
    var requisitionIncome: Double? = null
    var buildingLimit: Int? = null

    @OneToMany(mappedBy = "building", cascade = [CascadeType.ALL])
    var addons: MutableSet<BuildingAddon>? = null

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

    @OneToMany(mappedBy = "building", cascade = [CascadeType.ALL])
    var modifiers: MutableSet<BuildingModifiers> = mutableSetOf()

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

    @ManyToMany
    @JoinTable(name = "buildings_units",
        joinColumns = [JoinColumn(name = "building_id")],
        inverseJoinColumns = [JoinColumn(name = "unit_id")])
    var units: MutableSet<DowUnit>? = null

    @ManyToMany
    @JoinTable(name = "buildings_researches",
        joinColumns = [JoinColumn(name = "building_id")],
        inverseJoinColumns = [JoinColumn(name = "research_id")])
    var researches: MutableSet<Research>? = null

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

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

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

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


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

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

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

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

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

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

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

    @OneToMany(mappedBy = "building", cascade = [CascadeType.ALL])
    var buildingRequirements: MutableSet<BuildingRequirements> = mutableSetOf()

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

    fun toDto(buildingAddons: List<BuildingAddonDto>?, researches: List<ResearchShortDto>?, weapons: Set<WeaponSlotDto>, requirement: RequirementDto?): BuildingFullDto =
        BuildingFullDto(
            id!!,
            race?.toDto(),
            armorType?.toDto(),
            armorType2?.toDto(),
            name,
            description,
            filename!!,
            buildCostRequisition,
            buildCostPower,
            buildCostPopulation,
            buildCostFaith,
            buildCostSouls,
            buildCostTime,
            faithIncome,
            powerIncome,
            requisitionIncome,
            health,
            armour,
            healthRegeneration,
            sightRadius,
            detectRadius,
            repairMax,
            icon,
            modId!!,
            deathExplosions.map { it.toDto(modId!!) }.toSet(),
            buildingAddons?.sortedBy { it.name },
            abilities.map { it.toShortDto() }.sortedBy { it.name }.toSet(),
            researches,
            modifiers.map { it.toDto() },
            AffectedDataDto(
                affectedOnUnits.map { it.compressDto() }.toSet(),
                affectedOnSergeants.toShortDtoSet(),
                affectedOnBuildings.map { it.compressDto() }.toSet(),
                affectedOnWeapons.toShortDtoSet(),
            ),
            units?.toList()?.sortedBy { it.uiIndexHint }?.toUnitDto() ?: emptyList(),
            weapons,
            requirement,
            affectedResearches.map { it.toResearchShortDto() }.toSet(),
            uiHotkeyName,
        )


}
