package theorycrafter.fitting

import eve.data.EveItemType
import eve.data.SkillRequirement
import eve.data.SkillType


/**
 * A collection of all the skills of a character.
 */
class SkillSet(


    /**
     * The list of skills.
     */
    val skills: List<Skill>


) {


    /**
     * Maps the skills by their skill type id.
     */
    private val skillById = skills.associateBy { it.type.itemId }


    /**
     * Returns the skill of the given type.
     */
    operator fun get(type: SkillType): Skill =
        skillById[type.itemId] ?: error("SkillSet must provide skills of all types")


    /**
     * Returns whether this skill set fulfills the given [SkillRequirement].
     */
    fun fulfillsRequirement(requirement: SkillRequirement): Boolean {
        return skillById[requirement.skillId]!!.level.value >= requirement.level
    }


    /**
     * Returns whether the [SkillSet] fulfills all the skill requirements of the given item type.
     */
    fun fulfillsAllRequirements(itemType: EveItemType): Boolean =
        itemType.requiredSkills.all { this.fulfillsRequirement(it) }


    /**
     * Returns the list of the item's skill requirements unfulfilled by the skill set.
     */
    fun unfulfilledRequirements(itemType: EveItemType): List<SkillRequirement> =
        itemType.requiredSkills.filter { !this.fulfillsRequirement(it) }


    /**
     * Returns the list of skill requirements for all the given items.
     * For each required skill, only the requirement with the highest skill is returned.
     */
    fun unfullfilledRequirements(vararg itemTypes: Iterable<EveItemType>): List<SkillRequirement> {
        val requirementBySkillId = buildMap<Int, SkillRequirement> {
            itemTypes.forEach {
                for (itemType in it) {
                    for (requirement in itemType.requiredSkills) {
                        if (!fulfillsRequirement(requirement)) {
                            val existingRequirement = this[requirement.skillId]
                            if ((existingRequirement == null) || (requirement.level > existingRequirement.level))
                                this[requirement.skillId] = requirement
                        }
                    }
                }
            }
        }

        return requirementBySkillId.values.toList()
    }


}