class Solution {
    /**
     * Holds fixed mapping of roman numerals to their respective numeric value.
     */
    private val values =
        mapOf(
            'I' to 1,
            'V' to 5,
            'X' to 10,
            'L' to 50,
            'C' to 100,
            'D' to 500,
            'M' to 1000,
        )

    /**
     * Represents an accumulator for right fold when turning roman numeral into an integer value.
     * @property sum Holds the current sum of the accumulator.
     * @property next Holds the value of the previous roman numeral digit.
     */
    private data class Accumulator(val sum: Int = 0, val next: Int = 0) {
        /**
         * @param it Current roman numeral digit.
         * @return Sign that is to be used when modifying sum of the accumulator.
         */
        private fun sign(it: Int): Int =
            when (next > it) {
                true -> -1
                false -> 1
            }

        /**
         * @param it Currently processed roman numeral digit.
         * @return Correctly updated accumulator.
         */
        fun update(it: Int): Accumulator = copy(sum = sum + sign(it) * it, next = it)
    }

    fun romanToInt(s: String): Int =
        s
            .map { values[it]!! }
            .foldRight(Accumulator()) { it, acc ->
                acc.update(it)
            }
            .sum
}

fun main() {
    val s = Solution()

    val tests =
        mapOf(
            "I" to 1,
            "II" to 2,
            "III" to 3,
            "IV" to 4,
            "V" to 5,
            "VI" to 6,
            "VII" to 7,
            "VIII" to 8,
            "IX" to 9,
            "X" to 10,
            "LVIII" to 58,
            "MCMXCIV" to 1994,
        )

    tests.forEach { (num, i) ->
        check(s.romanToInt(num) == i) {
            "$num: ${s.romanToInt(num)} == $i"
        }
    }
}