// Package lua 提供 Lua 脚本嵌入能力
package lua

import (
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	glua "github.com/yuin/gopher-lua"
)

func TestTimerManagerAt(t *testing.T) {
	engine, err := NewEngine(DefaultConfig())
	require.NoError(t, err)
	defer engine.Close()

	manager := engine.TimerManager()
	require.NotNil(t, manager)

	// 创建 Lua 函数作为回调
	L := engine.GetLStateForTest()
	defer engine.PutLStateForTest(L)

	// 注册一个简单的回调函数
	callback := L.NewFunction(func(_ *glua.LState) int {
		return 0
	})

	// 创建定时器
	handle, err := manager.At(100*time.Millisecond, callback, nil)
	require.NoError(t, err)
	require.NotNil(t, handle)

	// 等待定时器触发
	time.Sleep(200 * time.Millisecond)

	// 定时器应该已完成（active count 回到 0）
	assert.Equal(t, int32(0), manager.ActiveCount())
}

func TestTimerManagerCancel(t *testing.T) {
	engine, err := NewEngine(DefaultConfig())
	require.NoError(t, err)
	defer engine.Close()

	manager := engine.TimerManager()

	L := engine.GetLStateForTest()
	defer engine.PutLStateForTest(L)
	callback := L.NewFunction(func(_ *glua.LState) int {
		return 0
	})

	// 创建定时器
	handle, err := manager.At(200*time.Millisecond, callback, nil)
	require.NoError(t, err)

	// 立即取消
	ok := manager.Cancel(handle)
	assert.True(t, ok)

	// 等待超过定时器时间
	time.Sleep(300 * time.Millisecond)

	// 定时器应该被取消，active count 为 0
	assert.Equal(t, int32(0), manager.ActiveCount())
}

func TestTimerManagerWaitAll(t *testing.T) {
	engine, err := NewEngine(DefaultConfig())
	require.NoError(t, err)
	defer engine.Close()

	manager := engine.TimerManager()

	L := engine.GetLStateForTest()

	// 创建多个定时器
	for range 3 {
		callback := L.NewFunction(func(_ *glua.LState) int {
			return 0
		})
		manager.At(50*time.Millisecond, callback, nil)
	}

	// 等待所有完成
	ok := manager.WaitAll(1 * time.Second)
	assert.True(t, ok)

	// active count 应该回到 0
	assert.Equal(t, int32(0), manager.ActiveCount())
}

func TestTimerLuaAPI(t *testing.T) {
	engine, err := NewEngine(DefaultConfig())
	require.NoError(t, err)
	defer engine.Close()

	L := engine.GetLStateForTest()
	defer engine.PutLStateForTest(L)

	// 注册 ngx.timer API
	ngx := L.NewTable()
	L.SetGlobal("ngx", ngx)
	RegisterTimerAPI(L, engine.TimerManager(), ngx)

	// 测试 ngx.timer.at
	err = L.DoString(`
		-- 创建无 upvalue 的定时器（回调不能捕获外部变量）
		local handle, err = ngx.timer.at(0.1, function()
			-- callback body (no upvalues)
		end)

		assert(handle ~= nil)
		assert(err == nil)

		-- 检查 running_count
		local running = ngx.timer.running_count()
		assert(running >= 1)
	`)
	require.NoError(t, err)
}

func TestTimerRunningCount(t *testing.T) {
	engine, err := NewEngine(DefaultConfig())
	require.NoError(t, err)
	defer engine.Close()

	manager := engine.TimerManager()

	// 初始应该为 0
	assert.Equal(t, int32(0), manager.ActiveCount())

	// 创建定时器
	callback := engine.GetLStateForTest().NewFunction(func(_ *glua.LState) int {
		return 0
	})

	handle, _ := manager.At(50*time.Millisecond, callback, nil)
	_ = handle

	// 刚创建后应该有活跃定时器（在定时器触发前）
	// 注意：由于简化实现，定时器执行很快，所以 active count 可能很快回到 0
	// 这里我们只验证定时器最终会完成

	// 等待完成
	time.Sleep(100 * time.Millisecond)

	// 应该回到 0
	assert.Equal(t, int32(0), manager.ActiveCount())
}

// TestTimerManager_CancelConcurrent 验证并发 Cancel 与定时器触发不会产生负 active 计数或 panic。
func TestTimerManager_CancelConcurrent(t *testing.T) {
	engine, err := NewEngine(DefaultConfig())
	require.NoError(t, err)
	defer engine.Close()

	manager := engine.TimerManager()

	L := engine.GetLStateForTest()
	defer engine.PutLStateForTest(L)

	var wg sync.WaitGroup
	for range 100 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			callback := L.NewFunction(func(_ *glua.LState) int {
				return 0
			})
			handle, err := manager.At(10*time.Millisecond, callback, nil)
			require.NoError(t, err)
			manager.Cancel(handle)
		}()
	}
	wg.Wait()

	// 等待所有定时器触发/取消完成
	time.Sleep(200 * time.Millisecond)

	// active 计数不应为负
	require.GreaterOrEqual(t, manager.ActiveCount(), int32(0))
	assert.Equal(t, int32(0), manager.ActiveCount())
}
