package me.msoucy.ptures.view

import me.msoucy.ptures.model.Creature
import me.msoucy.ptures.model.Skill
import me.msoucy.ptures.model.SkillChoice
import me.msoucy.ptures.model.Target
import me.msoucy.ptures.model.VisibleStatus

class SkillViewText(skill: Skill) : SkillView(skill) {
    override fun display() {
        println(skill.name)
    }

    override fun displayEnumerated(idx: Int) {
        println("- ${skill.name}")
    }
}

class CreatureViewText(playerId: Int, creature: Creature) : CreatureView(playerId, creature) {

    private val skillViews = creature.skills.map { SkillViewText(it) }

    private fun chooseSkillName(): Skill {
        println("Skills:")
        println("=======")
        skillViews.forEachIndexed { index, skillView ->
            skillView.displayEnumerated(index)
        }
        var chosenSkill: Skill? = null
        while (chosenSkill == null) {
            print("> ")
            val tmpName = readLine() ?: ""
            val possibleSkills = creature.skills.filter { it.name == tmpName }
            if (possibleSkills.isNotEmpty()) {
                chosenSkill = possibleSkills.first()
            }
        }
        return chosenSkill
    }

    private fun selectSingleTarget(possibleTargets: List<CreatureView>): Creature {
        println("Targets:")
        println("========")
        possibleTargets.forEach { c ->
            println("- ${c.creature.name}")
        }
        var chosen: Creature? = null
        while (chosen == null) {
            print("> ")
            val tmpName = readLine() ?: ""
            val possible = possibleTargets.filter { it.creature.name == tmpName }
            if (possible.isNotEmpty()) {
                chosen = possible.first().creature
            }
        }
        return chosen
    }

    private fun chooseTargets(skill: Skill, possibleTargets: List<CreatureView>): List<Creature> {
        val target = skill.damageSteps[0].target
        return when (target) {
            Target.Self -> listOf(creature)
            Target.Selected -> listOf(selectSingleTarget(possibleTargets))
            Target.Others -> possibleTargets.filter { it.creature != creature }.map { it.creature }
            Target.Opponents -> possibleTargets.filter { it.playerId != playerId }.map { it.creature }
            Target.All -> possibleTargets.map { it.creature }
        }
    }

    override fun chooseSkill(possibleTargets: List<CreatureView>) {

        if (creature.activeSkill == null) {
            val skill = chooseSkillName()
            val targets = chooseTargets(skill, possibleTargets)
            creature.activeSkill = SkillChoice(skill, targets)
        }
    }

    override fun displayHeader() {
        println("${creature.name}: ${creature.currentHp}/${creature.maxHp}")
    }

    override fun displayName() {
        println(creature.name)
    }

    override fun displaySkills() {
        skillViews.forEach { skillView ->
            skillView.display()
        }
    }

    override fun displayStatuses() {
        val displayables = creature.statuses.filterIsInstance<VisibleStatus>()
        if (displayables.isNotEmpty()) {
            println("Statuses")
            println("--------")
            displayables.forEach {
                println(it.label)
            }
        }
    }
}

class PlayerViewText(playerId: Int) : PlayerView(playerId) {
    override fun creatureViewFor(creature: Creature) = CreatureViewText(playerId, creature)
}

class BattleViewText : BattleView() {

    override fun useSkill(skillChoice: SkillChoice, attacker: Creature) {
        println("${attacker.name} used ${skillChoice.skill.name}!")
    }

    override fun reportDamage(dmg: Int) {
        if (dmg > 0) {
            println("Dealt $dmg damage!")
        } else if (dmg < 0) {
            println("Healed ${-dmg} health!")
        }
    }

}