// Package lua 提供 Lua 脚本嵌入能力。
//
// 该文件实现 LState 池，用于解决 gopher-lua 并发竞态问题。
// 每个请求从池中获取完全独立的 LState（各自拥有独立的 Global 对象），
// 彻底消除共享状态导致的 concurrent map read/write 问题。
//
// 设计要点：
//   - 每个 LState 独立创建，拥有独立的 Global 表
//   - 池化管理，避免频繁创建/销毁开销
//   - 动态伸缩，支持最大容量限制
//   - 工厂函数模式，统一 LState 初始化逻辑
//
// 作者：xfy
package lua

import (
	"sync"

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

// LStatePool 管理 LState 池。
//
// 每个请求从池中获取完全独立的 LState，彻底消除共享状态。
// 池支持动态伸缩，初始预热一定数量，运行时按需创建，
// 最大容量限制防止资源耗尽。
type LStatePool struct {
	mu      sync.Mutex
	pool    []*glua.LState
	factory func() *glua.LState
	maxSize int
	current int
}

// NewLStatePool 创建 LState 池。
//
// 参数：
//   - factory: LState 工厂函数，负责创建并初始化独立 LState
//   - initialSize: 初始池大小（预热数量）
//   - maxSize: 最大池大小（防止资源耗尽）
//
// 返回值：
//   - *LStatePool: 池实例
func NewLStatePool(factory func() *glua.LState, initialSize, maxSize int) *LStatePool {
	p := &LStatePool{
		pool:    make([]*glua.LState, 0, maxSize),
		factory: factory,
		maxSize: maxSize,
		current: 0,
	}

	// 预热：预先创建 initialSize 个 LState
	for range initialSize {
		L := p.factory()
		p.pool = append(p.pool, L)
		p.current++
	}

	return p
}

// Get 从池中获取一个 LState。
//
// 如果池中有可用 LState，直接返回；否则创建新的 LState（不超过 maxSize）。
//
// 返回值：
//   - *glua.LState: 可用的 LState 实例
//   - error: 池已满时返回错误
func (p *LStatePool) Get() *glua.LState {
	p.mu.Lock()
	defer p.mu.Unlock()

	// 池中有可用 LState
	if len(p.pool) > 0 {
		// 取出最后一个（避免数组移动）
		n := len(p.pool) - 1
		L := p.pool[n]
		p.pool[n] = nil // 防止内存泄漏
		p.pool = p.pool[:n]
		return L
	}

	// 池为空，检查是否可以创建新的
	if p.current >= p.maxSize {
		// 已达最大容量，等待或返回 nil
		// 这里选择返回 nil，由调用方处理
		return nil
	}

	// 创建新的 LState
	L := p.factory()
	p.current++
	return L
}

// Put 将 LState 归还池中。
//
// 归还前应确保 LState 处于干净状态（无残留数据）。
// 如果池已满（归还后超过 maxSize），直接关闭 LState。
//
// 参数：
//   - L: 要归还的 LState
func (p *LStatePool) Put(L *glua.LState) {
	if L == nil {
		return
	}

	p.mu.Lock()
	defer p.mu.Unlock()

	// 检查池容量
	if len(p.pool) >= p.maxSize {
		// 池已满，直接关闭
		L.Close()
		p.current--
		return
	}

	// 归还到池中
	p.pool = append(p.pool, L)
}

// Close 关闭池，释放所有 LState。
//
// 关闭所有池中的 LState，并清空池。
func (p *LStatePool) Close() {
	p.mu.Lock()
	defer p.mu.Unlock()

	// 关闭所有 LState
	for _, L := range p.pool {
		if L != nil {
			L.Close()
		}
	}
	p.pool = nil
	p.current = 0
}

// Size 返回池当前大小（包括已借出的）。
func (p *LStatePool) Size() int {
	p.mu.Lock()
	defer p.mu.Unlock()
	return p.current
}

// Available 返回池中可用的 LState 数量。
func (p *LStatePool) Available() int {
	p.mu.Lock()
	defer p.mu.Unlock()
	return len(p.pool)
}
