package me.msoucy.ptures.model

import com.badlogic.gdx.math.MathUtils.clamp
import com.badlogic.gdx.math.MathUtils.random

class Stats(var atk : Int, var def : Int, var spd : Int, var hp : Int)

class Creature {
    var name = ""
    val genes = Stats(5,5,5,5)
    val growth = Stats(0,0,0,0)
    val attributes = mutableMapOf<Attribute, Float>()
    var level = 1
    var currentHp = 1
    val skills = mutableListOf<Skill>()
    val statuses = mutableListOf<Status>()

    var activeSkill : SkillChoice? = null

    val atk : Int get() = statFormula(genes.atk, growth.atk)
    val def : Int get() = statFormula(genes.def, growth.def)
    val spd : Int get() = statFormula(genes.spd, growth.spd)
    val maxHp : Int get() = hpStatFormula(genes.hp, growth.hp)

    fun apply(dmg : Damage, attacker : Creature) {
        val critical = if (random(32) < attacker.genes.spd) { 1.5 } else { 1.0 }
        val randVal = random(0.85f, 1.0f)
        val atkAttribute = attacker.attributes.getOrElse(dmg.attribute) {1.0f}
        val defAttribute = attributes.getOrElse(dmg.attribute) {1.0f}
        val effectiveness = atkAttribute / defAttribute
        val modifier = critical * randVal * effectiveness * attacker.atkMod() * defMod()
        val power = (((0.4 * attacker.level) + 2) * dmg.power * (attacker.atk / def)) / 50 + 2
        val total = (power * modifier).toInt()
        currentHp = clamp(currentHp - total, 0, maxHp)

        if(currentHp == 0) {
            statuses.clear()
            addStatus(KnockedOut)
        } else {
            dmg.applyStatus(this)
        }
    }

    fun addStatus(status : Status) {
        if(status !in statuses)
        {
            statuses.add(status)
            status.onAdd(this)
        }
    }

    fun removeStatus(status : Status) {
        statuses.remove(status)
    }

    fun fullHeal() {
        currentHp = maxHp
        statuses.clear()
    }

    fun hits(creature : Creature, damage : Damage) =
            random(100) < damage.accuracy + spd - creature.spd

    inline fun <reified S : Status> hasStatus() = statuses.filterIsInstance<S>().isNotEmpty()

    private fun atkMod() = statuses.fold(1.0) { value, status -> value * status.attackMod(this) }
    private fun defMod() = statuses.map{ it.defenseMod(this) }.fold(1.0) { a, b -> a * b }

    private fun statFormula(gene : Int, growth : Int) = (2 * gene + growth / 4) * level / 100 + 5
    private fun hpStatFormula(gene : Int, growth : Int) = (2 * gene + growth / 4) * level / 100 + level + 10
}