// Package lua 提供 ngx.var API 实现。
//
// 该文件实现 nginx 变量访问的 Lua API，兼容 OpenResty/ngx_lua 语义。
// 支持：
//   - 标准 nginx 变量：request_method、request_uri、uri、query_string 等
//   - 请求头变量：http_host、http_user_agent、http_content_type 等
//   - 客户端信息：remote_addr、server_addr 等
//   - arg_ 前缀变量：arg_name 用于访问查询参数
//   - http_ 前缀变量：http_xxx 用于访问任意请求头
//   - 自定义变量存储：支持通过 store map 读写自定义变量
//
// 实现说明：
//   - 通过元表（__index/__newindex）实现动态变量读写
//   - 读取优先级：自定义变量 > fasthttp 内置变量
//   - 写入始终存储到自定义变量 store 中
//
// 作者：xfy
package lua

import (
	"strconv"
	"strings"

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

// argPrefix 是 arg_ 变量的前缀，用于获取查询参数
const argPrefix = "arg_"

// ngxVarAPI 封装 nginx 变量访问 API。
//
// 支持读取 fasthttp 请求中的标准 nginx 变量，
// 以及读写自定义变量（存储于 store map 中）。
type ngxVarAPI struct {
	// ctx 关联的 fasthttp 请求上下文
	ctx *fasthttp.RequestCtx

	// store 自定义变量存储，支持 Lua 脚本读写自定义变量
	store map[string]string
}

// newNgxVarAPI 创建 ngx.var API 实例。
//
// 参数：
//   - ctx: fasthttp 请求上下文
//
// 返回值：
//   - *ngxVarAPI: 初始化的 API 实例
func newNgxVarAPI(ctx *fasthttp.RequestCtx) *ngxVarAPI {
	return &ngxVarAPI{
		ctx:   ctx,
		store: make(map[string]string),
	}
}

// RegisterNgxVarAPI 在 Lua 状态机中注册 ngx.var API
// 使用元表实现动态读写：ngx.var.key 和 ngx.var[key]
func RegisterNgxVarAPI(L *glua.LState, api *ngxVarAPI, ngxTable *glua.LTable) {
	// 检查 ngx 表是否已存在 var 字段，避免重复写入
	if existing := ngxTable.RawGetString("var"); existing != glua.LNil {
		return
	}

	// 创建 ngx.var 表（使用元表实现动态访问）
	ngxVar := L.NewTable()

	// 创建元表
	mt := L.NewTable()

	// __index 元方法：读取变量
	mt.RawSetString("__index", L.NewFunction(api.luaVarIndex))

	// __newindex 元方法：设置变量
	mt.RawSetString("__newindex", L.NewFunction(api.luaVarNewIndex))

	// 设置元表
	L.SetMetatable(ngxVar, mt)

	// 将 ngx.var 添加到 ngx 表
	ngxTable.RawSetString("var", ngxVar)
}

// luaVarIndex 实现 ngx.var[key] 读取
// Lua 调用: local value = ngx.var.key 或 ngx.var[key]
func (api *ngxVarAPI) luaVarIndex(L *glua.LState) int {
	// 第一个参数是表本身（ngx.var）
	// 第二个参数是键名
	key := L.CheckString(2)

	// 1. 先查自定义变量存储
	if value, ok := api.store[key]; ok {
		L.Push(glua.LString(value))
		return 1
	}

	// 2. 从 fasthttp RequestCtx 获取变量
	// 某些变量需要返回数值类型（如 request_length）
	lv := api.getVariableLua(key)
	if lv != nil {
		L.Push(lv)
		return 1
	}

	// 3. 未找到变量，返回 nil
	L.Push(glua.LNil)
	return 1
}

// luaVarNewIndex 实现 ngx.var[key] = value 写入
// Lua 调用: ngx.var.key = value 或 ngx.var[key] = value
// 注意：Lua 的 nil 会被转换为空字符串存储
func (api *ngxVarAPI) luaVarNewIndex(L *glua.LState) int {
	// 第一个参数是表本身（ngx.var）
	// 第二个参数是键名
	// 第三个参数是值
	key := L.CheckString(2)
	value := L.OptString(3, "")

	// 存储到自定义变量存储（nil 会转换为空字符串）
	api.store[key] = value

	return 0
}

// getVariableLua 从 fasthttp RequestCtx 获取变量值，返回 Lua 类型
// 支持常见的 nginx 变量，某些变量返回数值类型
func (api *ngxVarAPI) getVariableLua(name string) glua.LValue {
	if api.ctx == nil {
		return nil
	}

	switch name {
	// HTTP 请求相关 - 数值类型
	case "request_length":
		return glua.LNumber(api.ctx.Request.Header.ContentLength())

	// HTTP 请求相关 - 字符串类型
	case "request_method":
		return glua.LString(string(api.ctx.Method()))
	case "request_uri":
		return glua.LString(string(api.ctx.RequestURI()))
	case "uri":
		return glua.LString(string(api.ctx.URI().Path()))
	case "document_uri":
		return glua.LString(string(api.ctx.URI().Path()))
	case "query_string", "args":
		return glua.LString(string(api.ctx.URI().QueryString()))
	case "server_protocol", "protocol":
		return glua.LString(string(api.ctx.Request.Header.Protocol()))
	case "scheme":
		return glua.LString(string(api.ctx.URI().Scheme()))
	case "request_time":
		// 简化实现，返回空字符串
		return glua.LString("")

	// 请求头相关
	case "http_host":
		return glua.LString(string(api.ctx.Host()))
	case "http_user_agent", "http_user-agent":
		return glua.LString(string(api.ctx.UserAgent()))
	case "http_referer":
		return glua.LString(string(api.ctx.Referer()))
	case "http_accept":
		return glua.LString(string(api.ctx.Request.Header.Peek("Accept")))
	case "http_accept_encoding", "http_accept-encoding":
		return glua.LString(string(api.ctx.Request.Header.Peek("Accept-Encoding")))
	case "http_accept_language", "http_accept-language":
		return glua.LString(string(api.ctx.Request.Header.Peek("Accept-Language")))
	case "http_connection":
		return glua.LString(string(api.ctx.Request.Header.Peek("Connection")))
	case "http_content_type", "http_content-type":
		return glua.LString(string(api.ctx.Request.Header.ContentType()))
	case "http_content_length", "http_content-length":
		return glua.LString(string(api.ctx.Request.Header.Peek("Content-Length")))

	// 客户端信息
	case "remote_addr":
		return glua.LString(api.ctx.RemoteAddr().String())
	case "remote_port":
		addr := api.ctx.RemoteAddr()
		if addr != nil {
			addrStr := addr.String()
			// IPv6 地址格式: [ip]:port，IPv4 格式: ip:port
			// 统一使用 LastIndex(":") 可正确处理两种格式
			if idx := strings.LastIndex(addrStr, ":"); idx >= 0 {
				return glua.LString(addrStr[idx+1:])
			}
		}
		return glua.LString("")
	case "binary_remote_addr":
		return glua.LString("")

	// 服务器信息
	case "server_addr":
		addr := api.ctx.LocalAddr()
		if addr != nil {
			return glua.LString(addr.String())
		}
		return glua.LString("")
	case "server_port":
		addr := api.ctx.LocalAddr()
		if addr != nil {
			addrStr := addr.String()
			if idx := strings.LastIndex(addrStr, ":"); idx >= 0 {
				return glua.LString(addrStr[idx+1:])
			}
		}
		return glua.LString("")
	case "server_name":
		return glua.LString(string(api.ctx.Host()))

	// URI 参数
	case argPrefix:
		// 获取所有参数
		return glua.LString(string(api.ctx.URI().QueryString()))
	default:
		// 检查是否是 arg_ 开头的参数
		if len(name) > len(argPrefix) && name[:len(argPrefix)] == argPrefix {
			paramName := name[4:]
			return glua.LString(string(api.ctx.QueryArgs().Peek(paramName)))
		}
		// 检查是否是 http_ 开头的请求头
		if len(name) > 5 && name[:5] == "http_" {
			headerName := name[5:]
			return glua.LString(string(api.ctx.Request.Header.Peek(headerName)))
		}
		return nil
	}
}

// getVariable 从 fasthttp RequestCtx 获取变量值（字符串形式）
// 用于 Go 层调用，内部复用 getVariableLua 实现
func (api *ngxVarAPI) getVariable(name string) string {
	lv := api.getVariableLua(name)
	if lv == nil {
		return ""
	}
	switch v := lv.(type) {
	case glua.LString:
		return string(v)
	case glua.LNumber:
		return strconv.Itoa(int(v))
	default:
		return lv.String()
	}
}

// SetVariable 设置自定义变量（Go 层调用）
func (api *ngxVarAPI) SetVariable(name, value string) {
	api.store[name] = value
}

// GetVariable 获取变量值（Go 层调用）
func (api *ngxVarAPI) GetVariable(name string) (string, bool) {
	// 先查自定义变量
	if value, ok := api.store[name]; ok {
		return value, true
	}
	// 再查 fasthttp 变量
	value := api.getVariable(name)
	return value, value != ""
}
