package server

import (
	"context"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"math/big"
	"net"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/valyala/fasthttp"
	"rua.plus/lolly/internal/cache"
	"rua.plus/lolly/internal/config"
	"rua.plus/lolly/internal/handler"
	"rua.plus/lolly/internal/lua"
	"rua.plus/lolly/internal/matcher"
	"rua.plus/lolly/internal/proxy"
	"rua.plus/lolly/internal/ssl"
	"rua.plus/lolly/internal/testutil"
)

// TestSetInternalRedirect 测试 SetInternalRedirect 标记内部重定向。
func TestSetInternalRedirect(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	SetInternalRedirect(ctx, "/internal/target")

	assert.True(t, IsInternalRedirect(ctx))
	assert.Equal(t, "/internal/target", GetInternalRedirectPath(ctx))
}

// TestIsInternalRedirect_未标记 测试未标记时返回 false。
func TestIsInternalRedirect_未标记(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	assert.False(t, IsInternalRedirect(ctx))
	assert.Equal(t, "", GetInternalRedirectPath(ctx))
}

// TestGetInternalRedirectPath_空路径 测试空路径重定向。
func TestGetInternalRedirectPath_空路径(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	SetInternalRedirect(ctx, "")
	assert.True(t, IsInternalRedirect(ctx))
	assert.Equal(t, "", GetInternalRedirectPath(ctx))
}

// TestInternalRedirect_多次设置 测试多次设置覆盖。
func TestInternalRedirect_多次设置(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	SetInternalRedirect(ctx, "/first")
	assert.Equal(t, "/first", GetInternalRedirectPath(ctx))

	SetInternalRedirect(ctx, "/second")
	assert.Equal(t, "/second", GetInternalRedirectPath(ctx))
}

// TestWrapRoutedHandler_无中间件 测试无中间件时原样返回。
func TestWrapRoutedHandler_无中间件(t *testing.T) {
	s := &Server{}
	called := false
	original := func(ctx *fasthttp.RequestCtx) {
		called = true
	}

	wrapped := s.wrapRoutedHandler(original)

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)
	wrapped(ctx)

	assert.True(t, called, "原始 handler 应被调用")
}

// TestWrapRoutedHandler_有AccessLog 测试带访问日志的包装。
func TestWrapRoutedHandler_有AccessLog(t *testing.T) {
	cfg := &config.Config{
		Logging: config.LoggingConfig{},
	}
	s := New(cfg)

	s.accessLogMiddleware = s.accessLogMiddleware

	called := false
	original := func(ctx *fasthttp.RequestCtx) {
		called = true
		ctx.SetBodyString("ok")
	}

	wrapped := s.wrapRoutedHandler(original)

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)
	wrapped(ctx)

	assert.True(t, called, "原始 handler 应被调用")
}

// TestWrapRoutedHandler_有ErrorPageManager 测试带错误页面管理器的包装。
func TestWrapRoutedHandler_有ErrorPageManager(t *testing.T) {
	tempDir := t.TempDir()
	errorPagePath := filepath.Join(tempDir, "404.html")
	err := os.WriteFile(errorPagePath, []byte("<html>Not Found</html>"), 0o644)
	require.NoError(t, err)

	epCfg := &config.ErrorPageConfig{
		Pages: map[int]string{404: errorPagePath},
	}
	epManager, err := handler.NewErrorPageManager(epCfg)
	require.NoError(t, err)

	s := &Server{
		errorPageManager: epManager,
	}

	called := false
	original := func(ctx *fasthttp.RequestCtx) {
		called = true
		ctx.SetBodyString("ok")
	}

	wrapped := s.wrapRoutedHandler(original)

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)
	wrapped(ctx)

	assert.True(t, called, "原始 handler 应被调用")
}

// TestConfigureStaticHandler_完整配置 测试完整的静态处理器配置。
func TestConfigureStaticHandler_完整配置(t *testing.T) {
	tempDir := t.TempDir()

	s := &Server{
		fileCache: cache.NewFileCache(100, 1024*1024, 5*time.Minute),
	}

	staticCfg := &config.StaticConfig{
		Path:    "/static",
		Root:    tempDir,
		Index:   []string{"index.html"},
		Alias:   "/data",
		Expires: "1h",
	}

	serverCfg := &config.ServerConfig{
		Compression: config.CompressionConfig{
			GzipStatic: true,
		},
	}

	h := s.configureStaticHandler(staticCfg, serverCfg)
	assert.NotNil(t, h)
}

// TestConfigureStaticHandler_自动索引 测试目录列表功能。
func TestConfigureStaticHandler_自动索引(t *testing.T) {
	tempDir := t.TempDir()

	s := &Server{}

	staticCfg := &config.StaticConfig{
		Path:               "/files",
		Root:               tempDir,
		AutoIndex:          true,
		AutoIndexFormat:    "html",
		AutoIndexLocaltime: true,
		AutoIndexExactSize: true,
	}

	serverCfg := &config.ServerConfig{}

	h := s.configureStaticHandler(staticCfg, serverCfg)
	assert.NotNil(t, h)
}

// TestConfigureStaticHandler_默认路径 测试空路径使用默认 "/"。
func TestConfigureStaticHandler_默认路径(t *testing.T) {
	tempDir := t.TempDir()

	s := &Server{}

	staticCfg := &config.StaticConfig{
		Root: tempDir,
	}

	serverCfg := &config.ServerConfig{}

	h := s.configureStaticHandler(staticCfg, serverCfg)
	assert.NotNil(t, h)
}

// TestConfigureStaticHandler_SymlinkCheck 测试符号链接安全检查配置。
func TestConfigureStaticHandler_SymlinkCheck(t *testing.T) {
	tempDir := t.TempDir()

	s := &Server{}

	staticCfg := &config.StaticConfig{
		Path:         "/static",
		Root:         tempDir,
		SymlinkCheck: true,
		Internal:     true,
	}

	serverCfg := &config.ServerConfig{}

	h := s.configureStaticHandler(staticCfg, serverCfg)
	assert.NotNil(t, h)
}

// TestPurgeByPath_带缓存代理 测试按路径清理带缓存的代理。
func TestPurgeByPath_带缓存代理(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{{Listen: ":0"}},
	}
	s := New(cfg)

	proxyCfg := &config.ProxyConfig{
		Path:        "/api",
		LoadBalance: "round_robin",
		Timeout:     config.ProxyTimeout{Connect: 5 * time.Second},
		Cache: config.ProxyCacheConfig{
			Enabled: true,
			MaxAge:  10 * time.Second,
		},
	}
	targets := testutil.NewTestTargets("http://localhost:8080")
	p, err := proxy.NewProxy(proxyCfg, targets, nil, nil)
	require.NoError(t, err)

	s.proxies = []*proxy.Proxy{p}

	purgeHandler := &PurgeHandler{server: s}

	deleted := purgeHandler.purgeByPath("/api/test", "GET")
	assert.Equal(t, 1, deleted)
}

// TestPurgeByPath_无缓存代理 测试无缓存代理时返回0。
func TestPurgeByPath_无缓存代理(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{{Listen: ":0"}},
	}
	s := New(cfg)

	proxyCfg := testutil.NewTestProxyConfig("/api")
	targets := testutil.NewTestTargets("http://localhost:8080")
	p, err := proxy.NewProxy(proxyCfg, targets, nil, nil)
	require.NoError(t, err)

	s.proxies = []*proxy.Proxy{p}

	purgeHandler := &PurgeHandler{server: s}

	deleted := purgeHandler.purgeByPath("/api/test", "GET")
	assert.Equal(t, 0, deleted)
}

// TestPurgeByPath_NilServer 测试 nil server 返回0。
func TestPurgeByPath_NilServer(t *testing.T) {
	purgeHandler := &PurgeHandler{server: nil}
	deleted := purgeHandler.purgeByPath("/api/test", "GET")
	assert.Equal(t, 0, deleted)
}

// TestPurgeByPattern_带缓存代理 测试按模式清理带缓存的代理。
func TestPurgeByPattern_带缓存代理(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{{Listen: ":0"}},
	}
	s := New(cfg)

	proxyCfg := &config.ProxyConfig{
		Path:        "/api",
		LoadBalance: "round_robin",
		Timeout:     config.ProxyTimeout{Connect: 5 * time.Second},
		Cache: config.ProxyCacheConfig{
			Enabled: true,
			MaxAge:  10 * time.Second,
		},
	}
	targets := testutil.NewTestTargets("http://localhost:8080")
	p, err := proxy.NewProxy(proxyCfg, targets, nil, nil)
	require.NoError(t, err)

	s.proxies = []*proxy.Proxy{p}

	purgeHandler := &PurgeHandler{server: s}

	deleted := purgeHandler.purgeByPattern("/api/*", "GET")
	assert.GreaterOrEqual(t, deleted, 0)
}

// TestPurgeByPattern_NilServer 测试 nil server 返回0。
func TestPurgeByPattern_NilServer(t *testing.T) {
	purgeHandler := &PurgeHandler{server: nil}
	deleted := purgeHandler.purgeByPattern("/api/*", "GET")
	assert.Equal(t, 0, deleted)
}

// TestPurgeByPattern_多代理 测试多代理的模式清理。
func TestPurgeByPattern_多代理(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{{Listen: ":0"}},
	}
	s := New(cfg)

	targets := testutil.NewTestTargets("http://localhost:8080")

	proxyCfg1 := &config.ProxyConfig{
		Path:        "/api",
		LoadBalance: "round_robin",
		Timeout:     config.ProxyTimeout{Connect: 5 * time.Second},
		Cache:       config.ProxyCacheConfig{Enabled: true, MaxAge: 10 * time.Second},
	}
	p1, err := proxy.NewProxy(proxyCfg1, targets, nil, nil)
	require.NoError(t, err)

	proxyCfg2 := &config.ProxyConfig{
		Path:        "/data",
		LoadBalance: "round_robin",
		Timeout:     config.ProxyTimeout{Connect: 5 * time.Second},
		Cache:       config.ProxyCacheConfig{Enabled: true, MaxAge: 20 * time.Second},
	}
	p2, err := proxy.NewProxy(proxyCfg2, targets, nil, nil)
	require.NoError(t, err)

	s.proxies = []*proxy.Proxy{p1, p2}

	purgeHandler := &PurgeHandler{server: s}
	deleted := purgeHandler.purgeByPattern("*", "GET")
	assert.GreaterOrEqual(t, deleted, 0)
}

// TestShutdownServers_NilCtx使用默认背景 测试 nil context 使用默认背景。
func TestShutdownServers_NilCtx使用默认背景(t *testing.T) {
	err := shutdownServers(nil, nil)
	assert.NoError(t, err)
}

// TestShutdownServers_Ctx取消 测试 context 取消。
func TestShutdownServers_Ctx取消(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	cancel()

	servers := []*fasthttp.Server{
		{Handler: func(ctx *fasthttp.RequestCtx) {}},
	}

	err := shutdownServers(ctx, servers)
	assert.Error(t, err)
	assert.True(t, errors.Is(err, context.Canceled))
}

// TestSetPidFile 测试设置 PID 文件路径。
func TestSetPidFile(t *testing.T) {
	mgr := NewUpgradeManager(nil)
	assert.Equal(t, "", mgr.pidFile)

	mgr.SetPidFile("/var/run/lolly.pid")
	assert.Equal(t, "/var/run/lolly.pid", mgr.pidFile)
}

// TestWritePid_写入文件 测试 PID 写入文件。
func TestWritePid_写入文件(t *testing.T) {
	tempDir := t.TempDir()
	pidFile := filepath.Join(tempDir, "lolly.pid")

	mgr := NewUpgradeManager(nil)
	mgr.SetPidFile(pidFile)

	err := mgr.WritePid()
	require.NoError(t, err)

	data, err := os.ReadFile(pidFile)
	require.NoError(t, err)

	expectedPid := fmt.Sprintf("%d", os.Getpid())
	assert.Equal(t, expectedPid, string(data))
}

// TestWritePid_覆盖写入 测试多次写入覆盖。
func TestWritePid_覆盖写入(t *testing.T) {
	tempDir := t.TempDir()
	pidFile := filepath.Join(tempDir, "lolly.pid")

	mgr := NewUpgradeManager(nil)
	mgr.SetPidFile(pidFile)

	err := mgr.WritePid()
	require.NoError(t, err)

	err = mgr.WritePid()
	require.NoError(t, err)

	data, err := os.ReadFile(pidFile)
	require.NoError(t, err)
	assert.Equal(t, fmt.Sprintf("%d", os.Getpid()), string(data))
}

// TestServeJSON_正常 测试正常 JSON 输出。
func TestServeJSON_正常(t *testing.T) {
	srv := New(nil)
	srv.startTime = time.Now()

	h := &StatusHandler{
		server: srv,
		path:   "/_status",
		format: "json",
	}

	status := &Status{
		Version:       "test",
		Uptime:        5 * time.Second,
		Connections:   10,
		Requests:      100,
		BytesSent:     2048,
		BytesReceived: 1024,
	}

	ctx := &fasthttp.RequestCtx{}
	h.serveJSON(ctx, status)

	assert.Equal(t, 200, ctx.Response.StatusCode())
	assert.Contains(t, string(ctx.Response.Header.ContentType()), "application/json")

	var parsed Status
	err := json.Unmarshal(ctx.Response.Body(), &parsed)
	require.NoError(t, err)
	assert.Equal(t, int64(10), parsed.Connections)
	assert.Equal(t, int64(100), parsed.Requests)
}

// TestServeJSON_无数据 测试最简 JSON 输出。
func TestServeJSON_无数据(t *testing.T) {
	srv := New(nil)
	srv.startTime = time.Now()

	h := &StatusHandler{
		server: srv,
		path:   "/_status",
		format: "json",
	}

	status := &Status{
		Version: "test",
	}

	ctx := &fasthttp.RequestCtx{}
	h.serveJSON(ctx, status)

	assert.Equal(t, 200, ctx.Response.StatusCode())

	var parsed Status
	err := json.Unmarshal(ctx.Response.Body(), &parsed)
	require.NoError(t, err)
	assert.Equal(t, "test", parsed.Version)
	assert.Nil(t, parsed.Cache)
	assert.Nil(t, parsed.Pool)
}

// TestMatchInheritedListener_UnixSocket 测试 Unix socket 继承匹配。
func TestMatchInheritedListener_UnixSocket(t *testing.T) {
	s := &Server{}

	dir := t.TempDir()
	socketPath := filepath.Join(dir, "test.sock")
	ln, err := net.Listen("unix", socketPath)
	require.NoError(t, err)
	defer ln.Close()

	inherited := []net.Listener{ln}

	result := s.matchInheritedListener(inherited, "unix:"+socketPath)
	assert.Equal(t, ln, result)
}

// TestMatchInheritedListener_UnixSocket不匹配 测试 Unix socket 地址不匹配。
func TestMatchInheritedListener_UnixSocket不匹配(t *testing.T) {
	s := &Server{}

	dir := t.TempDir()
	socketPath := filepath.Join(dir, "test.sock")
	ln, err := net.Listen("unix", socketPath)
	require.NoError(t, err)
	defer ln.Close()

	inherited := []net.Listener{ln}

	result := s.matchInheritedListener(inherited, "unix:"+dir+"/other.sock")
	assert.Nil(t, result)
}

// TestMatchInheritedListener_NilListener 测试列表中含 nil。
func TestMatchInheritedListener_NilListener(t *testing.T) {
	s := &Server{}

	ln, err := net.Listen("tcp", "127.0.0.1:0")
	require.NoError(t, err)
	defer ln.Close()

	inherited := []net.Listener{nil, ln}

	addr := ln.Addr().String()
	result := s.matchInheritedListener(inherited, addr)
	assert.Equal(t, ln, result)
}

// TestMatchInheritedListener_TCP网络不匹配 测试 TCP 非网络类型跳过。
func TestMatchInheritedListener_TCP网络不匹配(t *testing.T) {
	s := &Server{}

	dir := t.TempDir()
	socketPath := filepath.Join(dir, "test.sock")
	unixLn, err := net.Listen("unix", socketPath)
	require.NoError(t, err)
	defer unixLn.Close()

	inherited := []net.Listener{unixLn}

	result := s.matchInheritedListener(inherited, "127.0.0.1:8080")
	assert.Nil(t, result)
}

// TestMatchInheritedListener_端口不匹配 测试端口不同时不匹配。
func TestMatchInheritedListener_端口不匹配(t *testing.T) {
	s := &Server{}

	ln, err := net.Listen("tcp", "127.0.0.1:0")
	require.NoError(t, err)
	defer ln.Close()

	inherited := []net.Listener{ln}

	result := s.matchInheritedListener(inherited, "127.0.0.1:99999")
	assert.Nil(t, result)
}

// TestMatchInheritedListener_通配符匹配 测试 0.0.0.0 匹配任意地址。
func TestMatchInheritedListener_通配符匹配(t *testing.T) {
	s := &Server{}

	ln, err := net.Listen("tcp", "127.0.0.1:0")
	require.NoError(t, err)
	defer ln.Close()

	inherited := []net.Listener{ln}
	addr := ln.Addr().String()

	result := s.matchInheritedListener(inherited, "0.0.0.0"+addr[len("127.0.0.1"):])
	assert.Equal(t, ln, result)
}

// TestIsAnyAddr 测试 isAnyAddr 辅助函数。
func TestIsAnyAddr(t *testing.T) {
	tests := []struct {
		host string
		want bool
	}{
		{"0.0.0.0", true},
		{"::", true},
		{"", true},
		{"127.0.0.1", false},
		{"192.168.1.1", false},
	}

	for _, tt := range tests {
		t.Run(tt.host, func(t *testing.T) {
			assert.Equal(t, tt.want, isAnyAddr(tt.host))
		})
	}
}

// TestCreateFastServer 测试创建 fasthttp 服务器。
func TestCreateFastServer(t *testing.T) {
	s := &Server{}
	serverCfg := &config.ServerConfig{
		ReadTimeout:        10 * time.Second,
		WriteTimeout:       20 * time.Second,
		IdleTimeout:        30 * time.Second,
		MaxConnsPerIP:      100,
		MaxRequestsPerConn: 1000,
		Concurrency:        500,
		ReadBufferSize:     8192,
		WriteBufferSize:    8192,
		ServerTokens:       true,
	}

	handler := func(ctx *fasthttp.RequestCtx) {}
	fastSrv := s.createFastServer(serverCfg, handler)

	assert.NotNil(t, fastSrv)
	assert.Equal(t, 10*time.Second, fastSrv.ReadTimeout)
	assert.Equal(t, 20*time.Second, fastSrv.WriteTimeout)
	assert.Equal(t, 30*time.Second, fastSrv.IdleTimeout)
	assert.Equal(t, 100, fastSrv.MaxConnsPerIP)
	assert.Equal(t, 1000, fastSrv.MaxRequestsPerConn)
	assert.True(t, fastSrv.CloseOnShutdown)
	assert.Equal(t, 500, fastSrv.Concurrency)
	assert.Equal(t, 8192, fastSrv.ReadBufferSize)
	assert.Equal(t, 8192, fastSrv.WriteBufferSize)
}

// TestCreateFastServer_隐藏版本 测试 ServerTokens=false 时隐藏版本。
func TestCreateFastServer_隐藏版本(t *testing.T) {
	s := &Server{}
	serverCfg := &config.ServerConfig{
		ServerTokens: false,
	}

	fastSrv := s.createFastServer(serverCfg, nil)
	assert.Equal(t, "lolly", fastSrv.Name)
}

// TestRegisterRoute_各种类型 测试各种位置类型的路由注册。
func TestRegisterRoute_各种类型(t *testing.T) {
	s := &Server{
		locationEngine: matcher.NewLocationEngine(),
	}

	tests := []struct {
		name    string
		locType string
		path    string
	}{
		{"exact", matcher.LocationTypeExact, "/api/users"},
		{"prefix", matcher.LocationTypePrefix, "/api/"},
		{"prefix_priority", matcher.LocationTypePrefixPriority, "/api/v2/"},
		{"regex", matcher.LocationTypeRegex, "^/api/.*$"},
		{"regex_caseless", matcher.LocationTypeRegexCaseless, "^/API/.*$"},
		{"named", matcher.LocationTypeNamed, "@internal"},
		{"default", "", "/fallback/"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			le := matcher.NewLocationEngine()
			s.locationEngine = le

			h := func(ctx *fasthttp.RequestCtx) {}
			err := s.registerRoute(tt.locType, tt.path, h, false, "test")
			assert.NoError(t, err)
		})
	}
}

// TestRegisterProxyRoutesWithLocationEngine 测试代理路由注册到 LocationEngine。
func TestRegisterProxyRoutesWithLocationEngine(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{
			{
				Listen: ":0",
				Proxy: []config.ProxyConfig{
					{
						Path:        "/api",
						LoadBalance: "round_robin",
						Targets:     []config.ProxyTarget{{URL: "http://localhost:8080"}},
					},
				},
			},
		},
	}

	s := New(cfg)
	s.locationEngine = matcher.NewLocationEngine()

	err := s.registerProxyRoutesWithLocationEngine(&cfg.Servers[0])
	assert.NoError(t, err)
}

// TestRegisterProxyRoutesWithLocationEngine_命名路由 测试命名路由注册。
func TestRegisterProxyRoutesWithLocationEngine_命名路由(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{
			{
				Listen: ":0",
				Proxy: []config.ProxyConfig{
					{
						Path:         "/api",
						LoadBalance:  "round_robin",
						LocationType: matcher.LocationTypeNamed,
						LocationName: "backend",
						Targets:      []config.ProxyTarget{{URL: "http://localhost:8080"}},
					},
				},
			},
		},
	}

	s := New(cfg)
	s.locationEngine = matcher.NewLocationEngine()

	err := s.registerProxyRoutesWithLocationEngine(&cfg.Servers[0])
	assert.NoError(t, err)
}

// TestRegisterStaticHandlersWithLocationEngine 测试静态文件路由注册。
func TestRegisterStaticHandlersWithLocationEngine(t *testing.T) {
	tempDir := t.TempDir()

	cfg := &config.Config{
		Servers: []config.ServerConfig{
			{
				Listen: ":0",
				Static: []config.StaticConfig{
					{
						Path:  "/static",
						Root:  tempDir,
						Index: []string{"index.html"},
					},
				},
			},
		},
	}

	s := New(cfg)
	s.locationEngine = matcher.NewLocationEngine()

	err := s.registerStaticHandlersWithLocationEngine(&cfg.Servers[0])
	assert.NoError(t, err)
}

// TestRegisterLuaRoutesWithLocationEngine_无引擎 测试无 Lua 引擎时跳过。
func TestRegisterLuaRoutesWithLocationEngine_无引擎(t *testing.T) {
	s := &Server{luaEngine: nil}
	serverCfg := &config.ServerConfig{
		Lua: &config.LuaMiddlewareConfig{Enabled: true},
	}

	err := s.registerLuaRoutesWithLocationEngine(serverCfg)
	assert.NoError(t, err)
}

// TestRegisterLuaRoutesWithLocationEngine_未启用 测试 Lua 未启用时跳过。
func TestRegisterLuaRoutesWithLocationEngine_未启用(t *testing.T) {
	s := &Server{}
	serverCfg := &config.ServerConfig{
		Lua: &config.LuaMiddlewareConfig{Enabled: false},
	}

	err := s.registerLuaRoutesWithLocationEngine(serverCfg)
	assert.NoError(t, err)
}

// TestRegisterLuaRoutesWithLocationEngine_无路由 测试 Lua 脚本无路由时跳过。
func TestRegisterLuaRoutesWithLocationEngine_无路由(t *testing.T) {
	s := &Server{}
	serverCfg := &config.ServerConfig{
		Lua: &config.LuaMiddlewareConfig{
			Enabled: false,
			Scripts: []config.LuaScriptConfig{
				{Path: "/tmp/test.lua"},
			},
		},
	}

	err := s.registerLuaRoutesWithLocationEngine(serverCfg)
	assert.NoError(t, err)
}

// TestHandleRegistrationError_非冲突错误 测试非 ConflictError 返回错误。
func TestHandleRegistrationError_非冲突错误(t *testing.T) {
	s := &Server{}

	originalErr := fmt.Errorf("some registration error")
	err := s.handleRegistrationError("test", "/path", originalErr)

	assert.Error(t, err)
	assert.Contains(t, err.Error(), "test route /path")
}

// TestWrapHandler_带连接池 测试 wrapHandler 使用连接池。
func TestWrapHandler_带连接池(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{{Listen: ":0"}},
	}
	s := New(cfg)

	s.pool = NewGoroutinePool(PoolConfig{
		MaxWorkers:  10,
		MinWorkers:  2,
		QueueSize:   10,
		IdleTimeout: 5 * time.Second,
	})
	s.pool.Start()
	defer s.pool.Stop()

	base := func(ctx *fasthttp.RequestCtx) {
		ctx.SetBodyString("ok")
	}

	wrapped, err := s.wrapHandler(base, &cfg.Servers[0])
	require.NoError(t, err)
	assert.NotNil(t, wrapped)
}

// TestStopWithTimeout_默认超时 测试零超时使用默认值。
func TestStopWithTimeout_默认超时(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{{Listen: ":0"}},
	}
	s := New(cfg)

	err := s.StopWithTimeout(0)
	assert.NoError(t, err)
}

// TestStopWithTimeout_负超时 测试负超时使用默认值。
func TestStopWithTimeout_负超时(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{{Listen: ":0"}},
	}
	s := New(cfg)

	err := s.StopWithTimeout(-1 * time.Second)
	assert.NoError(t, err)
}

// TestCleanupResources_全nil 测试所有组件为 nil 时不 panic。
func TestCleanupResources_全nil(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{{Listen: ":0"}},
	}
	s := New(cfg)

	assert.NotPanics(t, func() {
		s.cleanupResources()
	})
}

// TestDupListener_关闭测试 测试复制后原 listener 仍可用。
func TestDupListener_关闭测试(t *testing.T) {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	require.NoError(t, err)
	defer ln.Close()

	duped, err := DupListener(ln)
	require.NoError(t, err)
	defer duped.Close()

	assert.Equal(t, ln.Addr().String(), duped.Addr().String())
}

// TestGetTLSConfig_有TLSManager 测试有 TLS 管理器时返回配置。
func TestGetTLSConfig_有TLSManager(t *testing.T) {
	tempDir := t.TempDir()
	certFile := filepath.Join(tempDir, "cert.pem")
	keyFile := filepath.Join(tempDir, "key.pem")

	err := generateSelfSignedCert(certFile, keyFile)
	if err != nil {
		t.Skipf("跳过: 无法生成测试证书: %v", err)
	}

	tlsMgr, err := ssl.NewTLSManager(&config.SSLConfig{
		Cert: certFile,
		Key:  keyFile,
	})
	if err != nil {
		t.Skipf("跳过: 无法创建 TLS 管理器: %v", err)
	}

	s := &Server{tlsManager: tlsMgr}

	tlsConfig, err := s.GetTLSConfig()
	assert.NoError(t, err)
	assert.NotNil(t, tlsConfig)
}

// generateSelfSignedCert 生成自签名证书用于测试。
func generateSelfSignedCert(certFile, keyFile string) error {
	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return err
	}

	template := &x509.Certificate{
		SerialNumber: big.NewInt(1),
		Subject: pkix.Name{
			Organization: []string{"Test"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(1 * time.Hour),
		KeyUsage:              x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
		IPAddresses:           []net.IP{net.ParseIP("127.0.0.1")},
		DNSNames:              []string{"localhost"},
	}

	certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
	if err != nil {
		return err
	}

	certOut, err := os.Create(certFile)
	if err != nil {
		return err
	}
	defer certOut.Close()

	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certDER}); err != nil {
		return err
	}

	keyOut, err := os.Create(keyFile)
	if err != nil {
		return err
	}
	defer keyOut.Close()

	keyBytes, err := x509.MarshalECPrivateKey(key)
	if err != nil {
		return err
	}

	return pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes})
}

// TestCreateListener_InheritedFromUpgradeManager 测试从 UpgradeManager 继承监听器。
func TestCreateListener_InheritedFromUpgradeManager(t *testing.T) {
	cfg := &config.Config{
		Servers: []config.ServerConfig{{Listen: "127.0.0.1:0"}},
	}
	s := New(cfg)

	ln, err := net.Listen("tcp", "127.0.0.1:0")
	require.NoError(t, err)
	defer ln.Close()

	um := NewUpgradeManager(s)
	um.SetPidFile("")
	s.SetUpgradeManager(um)

	addr := ln.Addr().String()
	cfg.Servers[0].Listen = addr

	s.SetListeners([]net.Listener{ln})

	matched, err := s.createListener(&cfg.Servers[0])
	require.NoError(t, err)
	assert.Equal(t, addr, matched.Addr().String())
}

// TestShutdownServers_成功关闭 测试正常关闭服务器。
func TestShutdownServers_成功关闭(t *testing.T) {
	srv1 := &fasthttp.Server{Handler: func(ctx *fasthttp.RequestCtx) {}}
	srv2 := &fasthttp.Server{Handler: func(ctx *fasthttp.RequestCtx) {}}

	ln1, err := net.Listen("tcp", "127.0.0.1:0")
	require.NoError(t, err)
	ln2, err := net.Listen("tcp", "127.0.0.1:0")
	require.NoError(t, err)

	go srv1.Serve(ln1)
	go srv2.Serve(ln2)
	time.Sleep(50 * time.Millisecond)

	err = shutdownServers(context.Background(), []*fasthttp.Server{srv1, srv2})
	assert.NoError(t, err)
}

// TestShutdownServers_Nil服务器跳过 测试列表中 nil 服务器被跳过。
func TestShutdownServers_Nil服务器跳过(t *testing.T) {
	srv := &fasthttp.Server{Handler: func(ctx *fasthttp.RequestCtx) {}}

	ln, err := net.Listen("tcp", "127.0.0.1:0")
	require.NoError(t, err)

	go srv.Serve(ln)
	time.Sleep(50 * time.Millisecond)

	err = shutdownServers(context.Background(), []*fasthttp.Server{nil, srv, nil})
	assert.NoError(t, err)
}

// TestRegisterLuaRoutesWithLocationEngine_有路由 测试带路由的 Lua 脚本注册。
func TestRegisterLuaRoutesWithLocationEngine_有路由(t *testing.T) {
	tempDir := t.TempDir()
	scriptPath := filepath.Join(tempDir, "test.lua")
	err := os.WriteFile(scriptPath, []byte("ngx.say('hello')"), 0o644)
	require.NoError(t, err)

	luaEngine, err := lua.NewEngine(lua.DefaultConfig())
	require.NoError(t, err)
	defer luaEngine.Close()

	s := &Server{
		luaEngine:      luaEngine,
		locationEngine: matcher.NewLocationEngine(),
	}

	serverCfg := &config.ServerConfig{
		Lua: &config.LuaMiddlewareConfig{
			Enabled: true,
			Scripts: []config.LuaScriptConfig{
				{
					Path:  scriptPath,
					Route: "/api/lua",
				},
			},
		},
	}

	err = s.registerLuaRoutesWithLocationEngine(serverCfg)
	assert.NoError(t, err)
}

// TestRegisterLuaRoutesWithLocationEngine_自定义路由类型 测试自定义 RouteType。
func TestRegisterLuaRoutesWithLocationEngine_自定义路由类型(t *testing.T) {
	tempDir := t.TempDir()
	scriptPath := filepath.Join(tempDir, "exact.lua")
	err := os.WriteFile(scriptPath, []byte("ngx.say('exact')"), 0o644)
	require.NoError(t, err)

	luaEngine, err := lua.NewEngine(lua.DefaultConfig())
	require.NoError(t, err)
	defer luaEngine.Close()

	s := &Server{
		luaEngine:      luaEngine,
		locationEngine: matcher.NewLocationEngine(),
	}

	serverCfg := &config.ServerConfig{
		Lua: &config.LuaMiddlewareConfig{
			Enabled: true,
			Scripts: []config.LuaScriptConfig{
				{
					Path:      scriptPath,
					Route:     "/api/exact",
					RouteType: matcher.LocationTypeExact,
				},
			},
		},
	}

	err = s.registerLuaRoutesWithLocationEngine(serverCfg)
	assert.NoError(t, err)
}

// TestRegisterLuaRoutesWithLocationEngine_自定义超时 测试自定义脚本超时。
func TestRegisterLuaRoutesWithLocationEngine_自定义超时(t *testing.T) {
	tempDir := t.TempDir()
	scriptPath := filepath.Join(tempDir, "timeout.lua")
	err := os.WriteFile(scriptPath, []byte("ngx.say('timeout')"), 0o644)
	require.NoError(t, err)

	luaEngine, err := lua.NewEngine(lua.DefaultConfig())
	require.NoError(t, err)
	defer luaEngine.Close()

	s := &Server{
		luaEngine:      luaEngine,
		locationEngine: matcher.NewLocationEngine(),
	}

	serverCfg := &config.ServerConfig{
		Lua: &config.LuaMiddlewareConfig{
			Enabled: true,
			Scripts: []config.LuaScriptConfig{
				{
					Path:    scriptPath,
					Route:   "/api/timeout",
					Timeout: 10 * time.Second,
				},
			},
		},
	}

	err = s.registerLuaRoutesWithLocationEngine(serverCfg)
	assert.NoError(t, err)
}

// TestServeHTTP_带缓存的Prometheus 测试 Prometheus 格式带缓存指标。
func TestServeHTTP_带缓存的Prometheus(t *testing.T) {
	cfg := &config.StatusConfig{
		Path:   "/_status",
		Format: "prometheus",
		Allow:  []string{},
	}

	srv := New(nil)
	srv.startTime = time.Now()
	srv.connections.Store(5)

	fc := cache.NewFileCache(100, 1024*1024, 5*time.Minute)
	srv.fileCache = fc

	h, err := NewStatusHandler(srv, cfg)
	require.NoError(t, err)

	ctx := &fasthttp.RequestCtx{}
	ctx.Request.SetRequestURI("/_status")
	h.ServeHTTP(ctx)

	assert.Equal(t, 200, ctx.Response.StatusCode())

	body := string(ctx.Response.Body())
	assert.Contains(t, body, "lolly_version")
	assert.Contains(t, body, "lolly_cache_entries")
}
