/*
 * Copyright 2026 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 micro-benchmarks for FieldRef and MethodCallRef PICs.
 */

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 PicBenchmarkTest {
    @Test
    fun benchmarkFieldGetSetPic() = runBlocking {
        val iterations = 300_000
        val script = """
            class C() {
                var x = 0
                fun add1() { x = x + 1 }
                fun getX() { x }
            }
            val c = C()
            var i = 0
            while(i < $iterations) {
                c.x = c.x + 1
                i = i + 1
            }
            c.x
        """.trimIndent()

        // PIC OFF
        PerfFlags.FIELD_PIC = false
        val scope1 = Scope()
        val t0 = System.nanoTime()
        val r1 = (scope1.eval(script) as ObjInt).value
        val t1 = System.nanoTime()
        println("[DEBUG_LOG] [BENCH] Field PIC=OFF: ${(t1 - t0) / 1_000_000.0} ms")
        assertEquals(iterations.toLong(), r1)

        // PIC ON
        PerfFlags.FIELD_PIC = true
        val scope2 = Scope()
        val t2 = System.nanoTime()
        val r2 = (scope2.eval(script) as ObjInt).value
        val t3 = System.nanoTime()
        println("[DEBUG_LOG] [BENCH] Field PIC=ON: ${(t3 - t2) / 1_000_000.0} ms")
        assertEquals(iterations.toLong(), r2)
        if (PerfFlags.PIC_DEBUG_COUNTERS) {
            println("[DEBUG_LOG] [PIC] field get hit=${net.sergeych.lyng.PerfStats.fieldPicHit} miss=${net.sergeych.lyng.PerfStats.fieldPicMiss}")
            println("[DEBUG_LOG] [PIC] field set hit=${net.sergeych.lyng.PerfStats.fieldPicSetHit} miss=${net.sergeych.lyng.PerfStats.fieldPicSetMiss}")
        }
    }

    @Test
    fun benchmarkMethodPic() = runBlocking {
        val iterations = 200_000
        val script = """
            class C() {
                var x = 0
                fun add(v) { x = x + v }
                fun get() { x }
            }
            val c = C()
            var i = 0
            while(i < $iterations) {
                c.add(1)
                i = i + 1
            }
            c.get()
        """.trimIndent()

        // PIC OFF
        PerfFlags.METHOD_PIC = false
        PerfFlags.SCOPE_POOL = false
        val scope1 = Scope()
        val t0 = System.nanoTime()
        val r1 = (scope1.eval(script) as ObjInt).value
        val t1 = System.nanoTime()
        println("[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: ${(t1 - t0) / 1_000_000.0} ms")
        assertEquals(iterations.toLong(), r1)

        // PIC ON
        PerfFlags.METHOD_PIC = true
        PerfFlags.SCOPE_POOL = true
        val scope2 = Scope()
        val t2 = System.nanoTime()
        val r2 = (scope2.eval(script) as ObjInt).value
        val t3 = System.nanoTime()
        println("[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: ${(t3 - t2) / 1_000_000.0} ms")
        assertEquals(iterations.toLong(), r2)
    }

    @Test
    fun benchmarkLoopScopePooling() = runBlocking {
        val iterations = 500_000
        val script = """
            var x = 0
            var i = 0
            while(i < $iterations) {
                if(true) {
                   var y = 1
                   x = x + y
                }
                i = i + 1
            }
            x
        """.trimIndent()

        // POOL OFF
        PerfFlags.SCOPE_POOL = false
        val scope1 = Scope()
        val t0 = System.nanoTime()
        val r1 = (scope1.eval(script) as ObjInt).value
        val t1 = System.nanoTime()
        println("[DEBUG_LOG] [BENCH] Loop Pool=OFF: ${(t1 - t0) / 1_000_000.0} ms")
        assertEquals(iterations.toLong(), r1)

        // POOL ON
        PerfFlags.SCOPE_POOL = true
        val scope2 = Scope()
        val t2 = System.nanoTime()
        val r2 = (scope2.eval(script) as ObjInt).value
        val t3 = System.nanoTime()
        println("[DEBUG_LOG] [BENCH] Loop Pool=ON: ${(t3 - t2) / 1_000_000.0} ms")
        assertEquals(iterations.toLong(), r2)
    }
}
