class ListNode(var `val`: Int) {
    var next: ListNode? = null
}

fun toListNode(vararg xs: Int): ListNode? {
    if (xs.isEmpty()) {
        return null
    }

    val dummy = ListNode(0)
    var node = dummy

    for (x in xs) {
        val next = ListNode(x)
        node.next = next
        node = next
    }

    return dummy.next
}

fun linkedListEquals(
    head: ListNode?,
    xs: List<Int>,
): Boolean {
    var node = head
    for ((i, x) in xs.withIndex()) {
        if (node == null) {
            println("[DEBUG] $x is expected at index $i in the linked list, but is not present")
            return false
        } else if (node.`val` != x) {
            println("[DEBUG] $x is expected at index $i in the linked list, but ${node.`val`} is present")
            return false
        }

        node = node.next
    }

    if (node != null) {
        println("[DEBUG] Linked list is longer than expected")
    }

    return node == null
}

class Solution {
    fun doubleIt(head: ListNode?): ListNode? {
        val dummyHead = ListNode(0)
        dummyHead.next = head

        val (newHead, carry) = doubleItRec(dummyHead)
        if (newHead!!.`val` > 0) {
            return newHead
        }
        return newHead.next
    }

    private fun doubleItRec(node: ListNode?): Pair<ListNode?, Int> {
        if (node == null) {
            return null to 0
        }

        val (nextHead, carry) = doubleItRec(node.next)
        val current = carry + 2 * node.`val`

        val newNode = ListNode(current % 10)
        newNode.next = nextHead

        return newNode to current / 10
    }
}

fun main() {
    val s = Solution()

    check(linkedListEquals(s.doubleIt(toListNode(1, 8, 9)), listOf(3, 7, 8)))
    check(linkedListEquals(s.doubleIt(toListNode(9, 9, 9)), listOf(1, 9, 9, 8)))
    check(linkedListEquals(s.doubleIt(toListNode(0)), listOf(0)))
}