package com.dowstats.service.w40k

import com.dowstats.Metadata
import com.dowstats.data.entities.*
import com.dowstats.data.entities.ModifiersBase.ModifiersBaseCompanion.fillDataFromRgdTable
import com.dowstats.data.entities.ModifiersBase.ModifiersBaseCompanion.filterUseless
import com.dowstats.data.entities.research.Research
import com.dowstats.data.entities.research.ResearchModifiers
import com.dowstats.data.entities.research.ResearchRequirements
import com.dowstats.data.rgd.RgdData
import com.dowstats.data.rgd.RgdDataUtil.getBooleanByName
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
import com.dowstats.data.rgd.RgdDataUtil.getIntByName
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

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

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

    fun extractToResearchEntity(
        fileName: String,
        modDictionary: Map<Int, String>,
        researchData: List<RgdData>,
        modFolderData: String,
        mod: Mod,
    ): Research {

        val research  = Research()
        research.filename = fileName

        val uiInfo = researchData.getRgdTableByName("ui_info") ?: throw Exception("Could not find ui_info at $fileName")
        val researchUiInfo = commonParseRgdService.getUiInfo(uiInfo, modDictionary, modFolderData, mod, log)
        research.name = researchUiInfo.name
        research.description = researchUiInfo.description
        research.uiIndexHint = researchData.getIntByName("ui_index_hint") ?: 0
        research.uiHotkeyName = researchData.getStringByName("ui_hotkey_name")
        research.icon = researchUiInfo.iconPath

        val cost = commonParseRgdService.getBuildCost(researchData.getRgdTableByName("time_cost"))

        research.costRequisition = cost.requisition
        research.costPower = cost.power
        research.costFaith = cost.faith
        research.costSouls = cost.souls
        research.costTime = cost.time
        research.researchModifiers = getResearchModifiers(research, researchData).toMutableSet()
        research.researchRequirements = getResearchRequirements(research, researchData).toMutableSet()

        research.modId = mod.id

        return research
    }

    private fun getResearchModifiers(research: Research, researchData: List<RgdData>): List<ResearchModifiers> {
        val modifiers = researchData.getRgdTableByName("modifiers")
        return modifiers?.mapNotNull { m ->
            if (m.name.contains("modifier_")) {
                val mTable = m.value as List<RgdData>
                if (mTable.getStringByName("\$REF") == "modifiers\\no_modifier.lua") null else {
                    ResearchModifiers().also {
                        it.research = research
                    }.fillDataFromRgdTable(mTable)
                }
            } else null
        }?.filterUseless() ?: emptyList()
    }

    private fun getResearchRequirements(research: Research, researchData: List<RgdData>): List<ResearchRequirements> {
        val requirements = researchData.getRgdTableByName("requirements")
        return requirements?.mapNotNull { r ->
            if (r.name.contains("required_")) {
                val rTable = r.value as List<RgdData>
                if (rTable.getStringByName("\$REF")?.contains(Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) == true) null else {
                    ResearchRequirements().also {
                        it.research = research
                        it.reference = rTable.getStringByName("\$REF")
                        it.value = commonParseRgdService.getRequirementReference(it.reference, rTable, research.filename!!, log)
                    }
                }
            } else null
        } ?: emptyList()
    }

}
