/*
 * Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

/*
 * JVM stress tests for scope frame pooling (deep nesting and recursion).
 */

import kotlinx.coroutines.runBlocking
import net.sergeych.lyng.PerfFlags
import net.sergeych.lyng.Scope
import net.sergeych.lyng.obj.ObjInt
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.Ignore

@Ignore("TODO(compile-time-res): legacy tests disabled")
class DeepPoolingStressJvmTest {
    @Test
    fun deepNestedCalls_noLeak_and_correct_with_and_without_pooling() = runBlocking {
        val depth = 200
        val script = """
            fun f0(x) { x + 1 }
            fun f1(x) { f0(x) + 1 }
            fun f2(x) { f1(x) + 1 }
            fun f3(x) { f2(x) + 1 }
            fun f4(x) { f3(x) + 1 }
            fun f5(x) { f4(x) + 1 }

            fun chain(x, d) {
                var i = 0
                var s = x
                while (i < d) {
                    // 5 nested calls per iteration
                    s = f5(s)
                    i = i + 1
                }
                s
            }
            chain(0, $depth)
        """.trimIndent()

        // Pool OFF
        PerfFlags.SCOPE_POOL = false
        val scope1 = Scope()
        val r1 = (scope1.eval(script) as ObjInt).value
        // Pool ON
        PerfFlags.SCOPE_POOL = true
        val scope2 = Scope()
        val r2 = (scope2.eval(script) as ObjInt).value
        // Each loop adds 6 (f0..f5 adds 6)
        val expected = 6L * depth
        assertEquals(expected, r1)
        assertEquals(expected, r2)
        // Reset
        PerfFlags.SCOPE_POOL = false
    }

    @Test
    fun recursion_factorial_correct_with_and_without_pooling() = runBlocking {
        val n = 10
        val script = """
            fun fact(x) {
                if (x <= 1) 1 else x * fact(x - 1)
            }
            fact($n)
        """.trimIndent()
        // OFF
        PerfFlags.SCOPE_POOL = false
        val scope1 = Scope()
        val r1 = (scope1.eval(script) as ObjInt).value
        // ON
        PerfFlags.SCOPE_POOL = true
        val scope2 = Scope()
        val r2 = (scope2.eval(script) as ObjInt).value
        // 10! = 3628800
        val expected = 3628800L
        assertEquals(expected, r1)
        assertEquals(expected, r2)
        PerfFlags.SCOPE_POOL = false
    }
}
