package com.dowstats.service.datamaps

import com.dowstats.Metadata.Requirements
import com.dowstats.data.dto.controllers.EntityCompressDtoObject.compressDto
import com.dowstats.data.dto.controllers.RequirementDto
import com.dowstats.data.dto.controllers.RequirementLimitByBuildingDto
import com.dowstats.data.dto.controllers.RequirementMobBonusDto
import com.dowstats.data.dto.controllers.RequirementResearchDto
import com.dowstats.data.dto.controllers.RequirementSquadsDto
import com.dowstats.data.entities.RequirementBase
import com.dowstats.data.repositories.AddonRepository
import com.dowstats.data.repositories.BuildingRepository
import com.dowstats.data.repositories.ResearchRepository
import com.dowstats.data.repositories.UnitRepository
import com.dowstats.service.datamaps.CommonMapping.toBuildingShortDto
import org.springframework.stereotype.Component

@Component
class RequirementsMappingComponent(
    val addonRepository: AddonRepository,
    val unitRepository: UnitRepository,
    val buildingRepository: BuildingRepository,
    val researchRepository: ResearchRepository,
) {
    fun getRequirements(requirements : List<RequirementBase>, modId: Long) : RequirementDto? {

        val requireCap =
            requirements.find { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_POP }?.value?.toDouble()
                ?.toInt()?.let { if(it == 0) null else it }

        val requiredOwnership =
            requirements.filter { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_OWNERSHIP }
                .mapNotNull { rro ->
                    rro.value
                }.toSet()

        val requirementAddon =
            requirements.find { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_ADDON }?.value?.let {
                val addonFileName = it.split("\\").last().replace(".lua", ".rgd")
                addonFileName.let {
                    addonRepository.findFirstByModIdAndFilename(
                        modId,
                        it.split("\\").last().replace(".lua", ".rgd")
                    )?.toShortDto()
                }
            }

        val requirementSquads =
            requirements.filter { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_SQUAD}.mapNotNull {req ->
                val unitName = req.value?.split(";")?.first()?.split("\\")?.last()?.replace(".lua", ".rgd")
                unitName?.let {
                    unitRepository.findFirstByModIdAndFilenameSquad(
                        modId,
                        it.split("\\").last().replace(".lua", ".rgd")
                    )?.compressDto()?.let {
                        RequirementSquadsDto(
                            it,
                            req.value?.split(";")?.last()?.toInt() ?: 1
                        )
                    }
                }
            }.toSet()

        val requirementAddonGlobal =
            requirements.filter { it.reference?.getPureReference()  == Requirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON }
                .mapNotNull { rgra ->
                    val addonFileName = rgra.value?.split("\\")?.last()?.replace(".lua", ".rgd")
                    addonFileName?.let {
                        addonRepository.findFirstByModIdAndFilename(
                            modId,
                            it.split("\\").last().replace(".lua", ".rgd")
                        )?.toShortDto()
                    }
                }.toSet()

        val requirementBuildings =
            requirements.filter { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_STRUCTURE }.mapNotNull {
                val buildingFileName = it.value?.split("\\")?.last()?.replace(".lua", ".rgd")
                buildingFileName?.let {
                    buildingRepository.findByModIdAndFilename(modId, buildingFileName)
                }
            }.distinct().toBuildingShortDto().toSet()

        val limitByBuilding = requirements.find { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_RATIO }?.let {
            val buildingFileName = it.value?.split(";")?.first()?.replace(".lua", ".rgd")
            val limitPerBuilding = it.value?.split(";")?.last()?.toInt() ?: 0

            buildingFileName
                ?.let {buildingRepository.findByModIdAndFilename(modId, it.split("\\").last().replace(".lua", ".rgd"))?.toBuildingShortDto()}
                ?.let {
                    RequirementLimitByBuildingDto(
                        it,
                        limitPerBuilding
                    )
                }
        }

        val requirementBuildingsEither =
            requirements.find { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER }?.let {
                it.value?.split(";")?.mapNotNull { bPath ->
                    buildingRepository.findByModIdAndFilename(
                        modId,
                        bPath.split("\\").last().replace(".lua", ".rgd")
                    )
                }
            }?.toBuildingShortDto()?.toSet() ?: emptySet()

        val requirementResearches =
            requirements.filter { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_RESEARCH }.mapNotNull {
                val research = it.value?.split(";")?.first()
                val mustNotBeCompleteStr = it.value?.split(";")?.last()
                val researchFileName = research?.split("\\")?.last()?.replace(".lua", ".rgd")?.let {
                    if(it.endsWith(".rgd"))  it else "$it.rgd"
                }
                researchFileName?.let {
                    researchRepository.findFirstByModIdAndFilename(modId, researchFileName)
                }?.toResearchShortDto()?.let {
                    val mustNotBeComplete = mustNotBeCompleteStr == "true"
                    RequirementResearchDto(it, mustNotBeComplete)
                }
            }.toSet()

        val requirementResearchEither =
            requirements.filter { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIRED_RESEARCH_EITHER }.mapNotNull {
                it.value?.split(";")?.mapNotNull { r ->
                    val researchFileName = r.split("\\").last().replace(".lua", ".rgd").let {resFile ->
                        if(resFile.endsWith(".rgd"))  resFile else "$resFile.rgd"
                    }

                    researchRepository.findFirstByModIdAndFilename(modId, researchFileName)?.toResearchShortDto()?.let {
                            RequirementResearchDto(it, false)
                        }
                }
            }.flatten().toSet()


        val requirementMobBonus =
            requirements.find { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_MOB_BONUS }?.let {
                RequirementMobBonusDto(
                    it.value?.split(";")?.first()?.toDouble() ?: 0.0,
                    runCatching  {
                        it.value?.split(";")?.last()?.toInt()
                    }.getOrNull() ?: 0
                )

            }

        val requirementStructureExclusive =
            requirements.find { it.reference?.getPureReference()  == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_EXCLUSIVE }?.let {
                it.value?.let { bPath ->
                    buildingRepository.findByModIdAndFilename(
                        modId,
                        bPath.split("\\").last().replace(".lua", ".rgd")
                    )
                }
            }?.toBuildingShortDto()

        val requirementAddonExclusive =
            requirements.find { it.reference?.getPureReference()  == Requirements.REFERENCE_LOCAL_REQUIRED_ADDON_EXCLUSIVE }?.let {
                it.value?.let { addonPath ->
                    addonRepository.findFirstByModIdAndFilename(
                        modId,
                        addonPath.split("\\").last().replace(".lua", ".rgd")
                    )
                }
            }?.toShortDto()

        return if (requirementBuildings.isNotEmpty() ||
            requirementBuildingsEither.isNotEmpty()  ||
            requirementResearches.isNotEmpty()  ||
            requirementSquads.isNotEmpty() ||
            requirementResearchEither.isNotEmpty() ||
            requirementAddon != null ||
            requirementAddonGlobal.isNotEmpty() ||
            requireCap != null ||
            limitByBuilding != null ||
            requirementMobBonus != null ||
            requirementStructureExclusive != null ||
            requirementAddonExclusive != null ||
            requiredOwnership.isNotEmpty()
        ) {
            RequirementDto(
                requirementBuildings,
                requirementBuildingsEither,
                requirementResearches,
                requirementSquads,
                requirementResearchEither,
                requirementAddon,
                requirementAddonGlobal,
                requireCap,
                limitByBuilding,
                requirementMobBonus,
                requirementStructureExclusive,
                requirementAddonExclusive,
                requiredOwnership
            )
        } else null
    }

    fun String.getPureReference(): String =
        this.split("\\").last()
            .replace(".lua", "")
            .replace(".rgd", "")


}