package com.pixelized.shared.lwa.usecase


import com.pixelized.shared.lwa.parser.dice.Dice
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

class RollUseCase {

    fun roll(dice: Dice): Int {
        return roll(
            modifier = dice.modifier,
            quantity = dice.quantity,
            faces = dice.faces,
        )
    }

    fun roll(
        modifier: Dice.Modifier? = null,
        quantity: Int = 1,
        faces: Int,
    ): Int {
        print("{")
        return sum(count = quantity) { left ->
            when (modifier) {
                Dice.Modifier.ADVANTAGE -> {
                    val roll1 = roll(faces = faces)
                    val roll2 = roll(faces = faces)
                    print("[$roll1,$roll2]")
                    max(roll1, roll2)
                }

                Dice.Modifier.DISADVANTAGE -> {
                    val roll1 = roll(faces = faces)
                    val roll2 = roll(faces = faces)
                    print("[$roll1,$roll2]")
                    min(roll1, roll2)
                }

                Dice.Modifier.EMPHASIS -> {
                    val roll1 = roll(faces = faces)
                    val roll2 = roll(faces = faces)
                    print("[$roll1,$roll2]")
                    val half = faces / 2
                    val roll1Abs = abs(half - roll1)
                    val roll2Abs = abs(half - roll2)
                    when {
                        roll1Abs == roll2Abs -> max(roll1, roll2)
                        roll1Abs < roll2Abs -> roll2
                        else -> roll1
                    }
                }

                null -> {
                    roll(faces = faces).also { print("$it") }
                }
            }.also {
                if (quantity > 1 && left != 1) print(",")
            }
        }.also {
            print("}")
        }
    }

    private fun roll(faces: Int): Int {
        return (Math.random() * faces.toDouble() + 1.0).toInt()
    }

    private fun sum(count: Int, block: (Int) -> Int): Int {
        return if (count > 1) {
            block(count) + sum(count - 1, block)
        } else {
            block(count)
        }
    }
}