package lua

import (
	"testing"
	"time"

	glua "github.com/yuin/gopher-lua"
)

// BenchmarkCoroutineCreation 测试协程创建开销
func BenchmarkCoroutineCreation(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	b.ResetTimer()
	for b.Loop() {
		coro, err := engine.NewCoroutine(nil)
		if err != nil {
			b.Fatal(err)
		}
		engine.releaseCoroutine(coro)
	}
}

// BenchmarkLuaContextPool 测试 LuaContext 池化开销
func BenchmarkLuaContextPool(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	b.ResetTimer()
	for b.Loop() {
		ctx := NewContext(engine, nil)
		ctx.SetVariable("key", "value")
		ctx.Write([]byte("hello"))
		ctx.SetPhase(PhaseContent)
		ctx.Release()
	}
}

// BenchmarkBytecodeCompilation 测试字节码编译开销
func BenchmarkBytecodeCompilation(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	script := `
		local x = 1 + 2
		local y = x * 3
		local z = "hello " .. "world"
		if y > 5 then
			return z
		end
		return x
	`

	b.ResetTimer()
	for b.Loop() {
		_, err := engine.CodeCache().GetOrCompileInline(script)
		if err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkSharedDictSetGet 测试共享字典读写开销
func BenchmarkSharedDictSetGet(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	dict := engine.CreateSharedDict("bench", 10000)

	b.ResetTimer()
	for b.Loop() {
		dict.Set("key", "value", 0)
		dict.Get("key")
	}
}

// BenchmarkTimerCallbackThroughput 测试定时器回调吞吐量
func BenchmarkTimerCallbackThroughput(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	manager := engine.TimerManager()
	callback := engine.GetLStateForTest().NewFunction(func(L *glua.LState) int {
		return 0
	})

	b.ResetTimer()
	for b.Loop() {
		manager.At(1*time.Millisecond, callback, nil)
	}
	b.StopTimer()

	// 等待所有定时器完成
	manager.WaitAll(5 * time.Second)
}

// BenchmarkTimerCallbackWithLuaExecution 测试带 Lua 执行的定时器回调
func BenchmarkTimerCallbackWithLuaExecution(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	L := engine.GetLStateForTest()
	ngx := L.NewTable()
	L.SetGlobal("ngx", ngx)
	RegisterTimerAPI(L, engine.TimerManager(), ngx)

	// 注册共享字典 API 供回调使用
	RegisterSharedDictAPI(L, engine.SharedDictManager(), ngx)

	// 简单的无 upvalue 回调
	script := `
		ngx.timer.at(0.001, function()
			-- empty callback
		end)
	`

	b.ResetTimer()
	for b.Loop() {
		if err := L.DoString(script); err != nil {
			b.Fatal(err)
		}
	}
	b.StopTimer()

	// 等待所有回调执行完成
	time.Sleep(100 * time.Millisecond)
}

// BenchmarkUpvalueDetection 测试 upvalue 检测开销
func BenchmarkUpvalueDetection(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	L := engine.GetLStateForTest()
	ngx := L.NewTable()
	L.SetGlobal("ngx", ngx)
	RegisterTimerAPI(L, engine.TimerManager(), ngx)

	b.ResetTimer()
	for b.Loop() {
		// 尝试注册带有 upvalue 的回调（应该被拒绝）
		err := L.DoString(`
			local x = 42
			local ok, err = ngx.timer.at(1, function() return x end)
		`)
		if err != nil {
			// 错误可能被 Lua 内部处理，检查返回值
			_ = err
		}
	}
}

// BenchmarkTimerGracefulShutdown 测试优雅关闭开销
func BenchmarkTimerGracefulShutdown(b *testing.B) {
	for b.Loop() {
		engine, err := NewEngine(DefaultConfig())
		if err != nil {
			b.Fatal(err)
		}

		manager := engine.TimerManager()
		callback := engine.GetLStateForTest().NewFunction(func(L *glua.LState) int {
			return 0
		})

		// 创建一些定时器
		for range 10 {
			manager.At(1*time.Millisecond, callback, nil)
		}

		// 关闭引擎（包含优雅关闭）
		engine.Close()
	}
}

// BenchmarkLuaContextPoolReuse 测试 LuaContext 池复用率。
// 验证多次获取/释放后池能否有效复用对象，减少分配。
func BenchmarkLuaContextPoolReuse(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	b.ReportAllocs()
	b.ResetTimer()
	for b.Loop() {
		// 模拟一次完整的请求生命周期
		ctx := NewContext(engine, nil)
		ctx.SetVariable("uri", "/test")
		ctx.SetVariable("method", "GET")
		ctx.SetPhase(PhaseContent)
		ctx.Write([]byte("response body"))
		ctx.FlushOutput()
		ctx.Release()
	}
}

// BenchmarkLuaCoroutinePoolThroughput 测试协程池吞吐量。
// 验证协程池在高频率创建/销毁场景下的复用效果。
func BenchmarkLuaCoroutinePoolThroughput(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	b.ReportAllocs()
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			coro, err := engine.NewCoroutine(nil)
			if err != nil {
				continue
			}
			coro.Close()
		}
	})
}

// BenchmarkLuaTablePool 测试 Lua table 对象池性能。
// 验证 table 创建和池复用在频繁 table 操作场景下的表现。
func BenchmarkLuaTablePool(b *testing.B) {
	engine, err := NewEngine(DefaultConfig())
	if err != nil {
		b.Fatal(err)
	}
	defer engine.Close()

	L := engine.GetLStateForTest()

	b.Run("NewTable_NoPool", func(b *testing.B) {
		b.ReportAllocs()
		b.ResetTimer()
		for b.Loop() {
			t := L.NewTable()
			t.RawSetString("key1", glua.LString("value1"))
			t.RawSetString("key2", glua.LString("value2"))
			t.RawSetString("key3", glua.LNumber(42))
		}
	})

	b.Run("SharedDict_AsPool", func(b *testing.B) {
		// 共享字典底层使用对象池存储条目
		dict := engine.CreateSharedDict("bench_pool", 1000)
		b.ReportAllocs()
		b.ResetTimer()
		for b.Loop() {
			dict.Set("key", "value_with_pool", 0)
			dict.Get("key")
			dict.Delete("key")
		}
	})
}
