// Package server 提供缓存清理处理器功能的测试。
//
// 该文件测试 PurgeHandler 模块的各项功能，包括：
//   - 路径配置（默认和自定义）
//   - localhost 特殊处理和 CIDR 解析
//   - IP 白名单访问控制
//   - Token 认证
//   - 请求处理流程（POST/方法检查）
//   - 请求体解析
//   - sendError 方法
//   - purgeByPath/purgeByPattern 方法（nil server）
//
// 作者：xfy
package server

import (
	"net"
	"strings"
	"testing"
	"time"

	"github.com/valyala/fasthttp"
	"rua.plus/lolly/internal/cache"
	"rua.plus/lolly/internal/config"
	"rua.plus/lolly/internal/loadbalance"
	"rua.plus/lolly/internal/proxy"
)

func TestPurgeHandler_Path(t *testing.T) {
	tests := []struct {
		name     string
		cfgPath  string
		wantPath string
	}{
		{
			name:     "default path",
			cfgPath:  "",
			wantPath: "/_cache/purge",
		},
		{
			name:     "custom path",
			cfgPath:  "/api/purge",
			wantPath: "/api/purge",
		},
		{
			name:     "custom path with version prefix",
			cfgPath:  "/api/v1/cache/purge",
			wantPath: "/api/v1/cache/purge",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			cfg := &config.CacheAPIConfig{
				Path:  tt.cfgPath,
				Allow: []string{},
			}

			h, err := NewPurgeHandler(nil, cfg)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}

			if h.Path() != tt.wantPath {
				t.Errorf("expected path %s, got %s", tt.wantPath, h.Path())
			}
		})
	}
}

func TestPurgeHandler_NewPurgeHandler(t *testing.T) {
	t.Run("localhost special handling", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{"localhost"},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		if len(h.allowed) != 2 {
			t.Fatalf("expected 2 allowed networks for localhost, got %d", len(h.allowed))
		}

		// 验证包含 127.0.0.1/32
		_, v4Net, _ := net.ParseCIDR("127.0.0.1/32")
		if v4Net == nil {
			t.Fatal("failed to parse 127.0.0.1/32")
		}
		foundV4 := false
		for _, n := range h.allowed {
			if n.String() == v4Net.String() {
				foundV4 = true
				break
			}
		}
		if !foundV4 {
			t.Error("expected 127.0.0.1/32 in allowed networks")
		}

		// 验证包含 ::1/128
		_, v6Net, _ := net.ParseCIDR("::1/128")
		if v6Net == nil {
			t.Fatal("failed to parse ::1/128")
		}
		foundV6 := false
		for _, n := range h.allowed {
			if n.String() == v6Net.String() {
				foundV6 = true
				break
			}
		}
		if !foundV6 {
			t.Error("expected ::1/128 in allowed networks")
		}
	})

	t.Run("CIDR parsing", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{"10.0.0.0/8", "172.16.0.0/12"},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		if len(h.allowed) != 2 {
			t.Errorf("expected 2 allowed networks, got %d", len(h.allowed))
		}
	})

	t.Run("single IP parsed as CIDR", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{"192.168.1.100"},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		if len(h.allowed) != 1 {
			t.Fatalf("expected 1 allowed network, got %d", len(h.allowed))
		}

		// 单 IP 应转换为 /32 CIDR
		if h.allowed[0].String() != "192.168.1.100/32" {
			t.Errorf("expected 192.168.1.100/32, got %s", h.allowed[0].String())
		}
	})

	t.Run("invalid IP returns error", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{"not-an-ip"},
		}

		_, err := NewPurgeHandler(nil, cfg)
		if err == nil {
			t.Error("expected error for invalid IP, got nil")
		}
	})
}

func TestPurgeHandler_checkAccess(t *testing.T) {
	tests := []struct {
		name       string
		allow      []string
		clientIP   string
		wantAccess bool
	}{
		{
			name:       "no allow list - open access",
			allow:      []string{},
			clientIP:   "1.2.3.4",
			wantAccess: true,
		},
		{
			name:       "CIDR match",
			allow:      []string{"192.168.0.0/16"},
			clientIP:   "192.168.1.100",
			wantAccess: true,
		},
		{
			name:       "CIDR no match",
			allow:      []string{"10.0.0.0/8"},
			clientIP:   "192.168.1.100",
			wantAccess: false,
		},
		{
			name:       "single IP match",
			allow:      []string{"127.0.0.1"},
			clientIP:   "127.0.0.1",
			wantAccess: true,
		},
		{
			name:       "single IP no match",
			allow:      []string{"127.0.0.1"},
			clientIP:   "127.0.0.2",
			wantAccess: false,
		},
		{
			name:       "localhost allows 127.0.0.1",
			allow:      []string{"localhost"},
			clientIP:   "127.0.0.1",
			wantAccess: true,
		},
		{
			name:       "localhost allows ::1",
			allow:      []string{"localhost"},
			clientIP:   "::1",
			wantAccess: true,
		},
		{
			name:       "localhost denies other IP",
			allow:      []string{"localhost"},
			clientIP:   "10.0.0.1",
			wantAccess: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			cfg := &config.CacheAPIConfig{
				Path:  "/_cache/purge",
				Allow: tt.allow,
			}

			h, err := NewPurgeHandler(nil, cfg)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}

			if len(h.allowed) == 0 {
				// 无白名单时应允许所有访问
				if !h.checkAccess(nil) {
					t.Error("expected access to be true when no allow list configured")
				}
				return
			}

			// 直接测试 IP 是否在 allowed 列表中
			ip := net.ParseIP(tt.clientIP)
			if ip == nil {
				t.Fatalf("failed to parse client IP: %s", tt.clientIP)
			}

			found := false
			for _, network := range h.allowed {
				if network.Contains(ip) {
					found = true
					break
				}
			}

			if found != tt.wantAccess {
				t.Errorf("expected access %v, got %v", tt.wantAccess, found)
			}
		})
	}
}

func TestPurgeHandler_checkAuth(t *testing.T) {
	t.Run("no auth configured", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path: "/_cache/purge",
			Auth: config.CacheAPIAuthConfig{
				Type:  "",
				Token: "",
			},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		ctx := &fasthttp.RequestCtx{}
		if !h.checkAuth(ctx) {
			t.Error("expected auth to pass when no auth configured")
		}
	})

	t.Run("auth type none", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path: "/_cache/purge",
			Auth: config.CacheAPIAuthConfig{
				Type:  "none",
				Token: "",
			},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		ctx := &fasthttp.RequestCtx{}
		if !h.checkAuth(ctx) {
			t.Error("expected auth to pass when type is none")
		}
	})

	t.Run("token auth - correct Bearer token", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path: "/_cache/purge",
			Auth: config.CacheAPIAuthConfig{
				Type:  "token",
				Token: "secret-token",
			},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		ctx := &fasthttp.RequestCtx{}
		ctx.Request.Header.Set("Authorization", "Bearer secret-token")

		if !h.checkAuth(ctx) {
			t.Error("expected auth to pass with correct Bearer token")
		}
	})

	t.Run("token auth - correct direct token", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path: "/_cache/purge",
			Auth: config.CacheAPIAuthConfig{
				Type:  "token",
				Token: "secret-token",
			},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		ctx := &fasthttp.RequestCtx{}
		ctx.Request.Header.Set("Authorization", "secret-token")

		if !h.checkAuth(ctx) {
			t.Error("expected auth to pass with correct direct token")
		}
	})

	t.Run("token auth - wrong token", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path: "/_cache/purge",
			Auth: config.CacheAPIAuthConfig{
				Type:  "token",
				Token: "secret-token",
			},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		ctx := &fasthttp.RequestCtx{}
		ctx.Request.Header.Set("Authorization", "Bearer wrong-token")

		if h.checkAuth(ctx) {
			t.Error("expected auth to fail with wrong token")
		}
	})

	t.Run("token auth - missing header", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path: "/_cache/purge",
			Auth: config.CacheAPIAuthConfig{
				Type:  "token",
				Token: "secret-token",
			},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		ctx := &fasthttp.RequestCtx{}

		if h.checkAuth(ctx) {
			t.Error("expected auth to fail when Authorization header is missing")
		}
	})

	t.Run("token auth - unknown type", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path: "/_cache/purge",
			Auth: config.CacheAPIAuthConfig{
				Type:  "basic",
				Token: "secret-token",
			},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		ctx := &fasthttp.RequestCtx{}
		ctx.Request.Header.Set("Authorization", "Bearer secret-token")

		if h.checkAuth(ctx) {
			t.Error("expected auth to fail for unknown auth type")
		}
	})
}

// TestPurgeHandler_ServeHTTP_MethodCheck 测试 ServeHTTP 的方法检查。
func TestPurgeHandler_ServeHTTP_MethodCheck(t *testing.T) {
	methods := []string{"GET", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"}

	for _, method := range methods {
		t.Run(method, func(t *testing.T) {
			cfg := &config.CacheAPIConfig{
				Path:  "/_cache/purge",
				Allow: []string{},
			}

			h, err := NewPurgeHandler(nil, cfg)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}

			ctx := &fasthttp.RequestCtx{}
			ctx.Init(&fasthttp.Request{}, nil, nil)
			ctx.Request.Header.SetMethod(method)

			h.ServeHTTP(ctx)

			if ctx.Response.StatusCode() != fasthttp.StatusMethodNotAllowed {
				t.Errorf("expected status %d for method %s, got %d", fasthttp.StatusMethodNotAllowed, method, ctx.Response.StatusCode())
			}

			// 验证响应体包含错误信息
			if !strings.Contains(string(ctx.Response.Body()), "method not allowed") {
				t.Errorf("expected 'method not allowed' in response body, got: %s", string(ctx.Response.Body()))
			}
		})
	}
}

// TestPurgeHandler_ServeHTTP_RequestBodyParsing 测试请求体解析。
func TestPurgeHandler_ServeHTTP_RequestBodyParsing(t *testing.T) {
	tests := []struct {
		name       string
		body       string
		wantStatus int
	}{
		{
			name:       "invalid JSON",
			body:       "{invalid json}",
			wantStatus: fasthttp.StatusBadRequest,
		},
		{
			name:       "empty JSON",
			body:       "{}",
			wantStatus: fasthttp.StatusBadRequest,
		},
		{
			name:       "missing path and pattern",
			body:       `{"method": "GET"}`,
			wantStatus: fasthttp.StatusBadRequest,
		},
		{
			name:       "only path",
			body:       `{"path": "/test"}`,
			wantStatus: fasthttp.StatusOK,
		},
		{
			name:       "only pattern",
			body:       `{"pattern": "/api/*"}`,
			wantStatus: fasthttp.StatusOK,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			cfg := &config.CacheAPIConfig{
				Path:  "/_cache/purge",
				Allow: []string{},
			}

			h, err := NewPurgeHandler(nil, cfg)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}

			ctx := &fasthttp.RequestCtx{}
			ctx.Init(&fasthttp.Request{}, nil, nil)
			ctx.Request.Header.SetMethod("POST")
			ctx.Request.SetBodyString(tt.body)

			h.ServeHTTP(ctx)

			if ctx.Response.StatusCode() != tt.wantStatus {
				t.Errorf("expected status %d, got %d", tt.wantStatus, ctx.Response.StatusCode())
			}
		})
	}
}

// TestPurgeHandler_PurgeResponse 测试 purge 响应格式。
func TestPurgeHandler_PurgeResponse(t *testing.T) {
	cfg := &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	}

	h, err := NewPurgeHandler(nil, cfg)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)
	ctx.Request.Header.SetMethod("POST")
	ctx.Request.SetBodyString(`{"path": "/test"}`)

	h.ServeHTTP(ctx)

	// 验证响应
	if ctx.Response.StatusCode() != fasthttp.StatusOK {
		t.Errorf("expected status %d, got %d", fasthttp.StatusOK, ctx.Response.StatusCode())
	}

	// 验证响应体格式
	body := string(ctx.Response.Body())
	if !strings.Contains(body, `"deleted"`) {
		t.Errorf("expected 'deleted' field in response body, got: %s", body)
	}
}

// TestPurgeHandler_SendError 测试 sendError 方法的错误响应格式。
func TestPurgeHandler_SendError(t *testing.T) {
	tests := []struct {
		name     string
		status   int
		errMsg   string
		wantBody string
	}{
		{
			name:     "bad request",
			status:   fasthttp.StatusBadRequest,
			errMsg:   "invalid request",
			wantBody: `{"error":"invalid request"}`,
		},
		{
			name:     "forbidden",
			status:   fasthttp.StatusForbidden,
			errMsg:   "access denied",
			wantBody: `{"error":"access denied"}`,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			cfg := &config.CacheAPIConfig{
				Path:  "/_cache/purge",
				Allow: []string{},
			}

			h, err := NewPurgeHandler(nil, cfg)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}

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

			h.sendError(ctx, tt.status, tt.errMsg)

			if ctx.Response.StatusCode() != tt.status {
				t.Errorf("expected status %d, got %d", tt.status, ctx.Response.StatusCode())
			}

			body := string(ctx.Response.Body())
			if !strings.Contains(body, tt.errMsg) {
				t.Errorf("expected '%s' in response body, got: %s", tt.errMsg, body)
			}

			// 验证内容类型
			contentType := string(ctx.Response.Header.ContentType())
			if contentType != "application/json; charset=utf-8" {
				t.Errorf("expected content-type 'application/json; charset=utf-8', got: %s", contentType)
			}
		})
	}
}

// TestPurgeHandler_PurgeByPath 测试 purgeByPath 方法（nil server）。
func TestPurgeHandler_PurgeByPath(t *testing.T) {
	h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 验证 nil server 时返回 0
	deleted := h.PurgeByPathForTest("/test", "GET")
	if deleted != 0 {
		t.Errorf("expected 0 deletions for nil server, got %d", deleted)
	}
}

// TestPurgeHandler_PurgeByPattern 测试 purgeByPattern 方法（nil server）。
func TestPurgeHandler_PurgeByPattern(t *testing.T) {
	h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 验证 nil server 时返回 0
	deleted := h.PurgeByPatternForTest("/api/*", "GET")
	if deleted != 0 {
		t.Errorf("expected 0 deletions for nil server, got %d", deleted)
	}
}

// TestPurgeHandler_CacheKeyWithMethod 测试带方法的缓存键。
func TestPurgeHandler_CacheKeyWithMethod(t *testing.T) {
	tests := []struct {
		path   string
		method string
	}{
		{"/test", "GET"},
		{"/test", "POST"},
		{"/api/users", "GET"},
		{"/api/users", "DELETE"},
	}

	for _, tt := range tests {
		t.Run(tt.path+"_"+tt.method, func(t *testing.T) {
			key := cache.HashPathWithMethod(tt.path, tt.method)
			if key == 0 {
				t.Error("expected non-zero hash key")
			}

			// 同一路径和方法应该产生相同的键
			key2 := cache.HashPathWithMethod(tt.path, tt.method)
			if key != key2 {
				t.Errorf("expected same key for same inputs, got %d and %d", key, key2)
			}

			// 同一路径不同方法应该产生不同的键
			key3 := cache.HashPathWithMethod(tt.path, "OTHER")
			if key == key3 {
				t.Errorf("expected different key for different method, got %d and %d", key, key3)
			}
		})
	}
}

// TestPurgeHandler_EmptyMethodDefaultsToGET 测试空方法默认为 GET。
func TestPurgeHandler_EmptyMethodDefaultsToGET(t *testing.T) {
	key1 := cache.HashPathWithMethod("/test", "")
	key2 := cache.HashPathWithMethod("/test", "GET")

	if key1 != key2 {
		t.Errorf("expected same key for empty and 'GET' method, got %d and %d", key1, key2)
	}
}

// TestPurgeHandler_checkAccess_NilContext 测试 checkAccess 处理。
func TestPurgeHandler_checkAccess_NilContext(t *testing.T) {
	t.Run("empty allow list allows all", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// Empty allow list should allow access (returns true even with nil context)
		if !h.checkAccess(nil) {
			t.Error("expected checkAccess to return true with empty allow list")
		}
	})
}

// TestPurgeHandler_PurgeByPath_NilServer 测试 purgeByPath 处理 nil server。
func TestPurgeHandler_PurgeByPath_NilServer(t *testing.T) {
	cfg := &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	}

	h, err := NewPurgeHandler(nil, cfg)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Should return 0 when server is nil
	deleted := h.PurgeByPathForTest("/test", "GET")
	if deleted != 0 {
		t.Errorf("expected 0 deletions for nil server, got %d", deleted)
	}
}

// TestPurgeHandler_PurgeByPattern_NilServer 测试 purgeByPattern 处理 nil server。
func TestPurgeHandler_PurgeByPattern_NilServer(t *testing.T) {
	cfg := &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	}

	h, err := NewPurgeHandler(nil, cfg)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Should return 0 when server is nil
	deleted := h.PurgeByPatternForTest("/api/*", "GET")
	if deleted != 0 {
		t.Errorf("expected 0 deletions for nil server, got %d", deleted)
	}
}

// TestPurgeHandler_ServeHTTP_WithAllowList 测试带白名单的请求处理。
func TestPurgeHandler_ServeHTTP_WithAllowList(t *testing.T) {
	cfg := &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{"192.168.0.0/16"},
	}

	h, err := NewPurgeHandler(nil, cfg)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 测试 POST 请求（会尝试访问控制检查）
	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)
	ctx.Request.Header.SetMethod("POST")
	ctx.Request.SetBodyString(`{"path": "/test"}`)

	h.ServeHTTP(ctx)

	// 由于无法设置 RemoteIP，checkAccess 会返回 false
	// 所以应该返回 403
	if ctx.Response.StatusCode() != fasthttp.StatusForbidden {
		t.Logf("Status: %d, Body: %s", ctx.Response.StatusCode(), string(ctx.Response.Body()))
	}
}

// TestPurgeHandler_checkAccess_WithAllowedIP 测试 checkAccess 方法。
func TestPurgeHandler_checkAccess_WithAllowedIP(t *testing.T) {
	t.Run("with allow list and nil remote", func(t *testing.T) {
		cfg := &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{"192.168.0.0/16"},
		}

		h, err := NewPurgeHandler(nil, cfg)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// Create a valid context but with nil remote address
		ctx := &fasthttp.RequestCtx{}
		ctx.Init(&fasthttp.Request{}, nil, nil)

		// context with nil remote address - should return false (no client IP)
		if h.checkAccess(ctx) {
			t.Error("expected checkAccess to return false with no client IP")
		}
	})
}

// mockProxyWithCache 是一个用于测试的 mock Proxy，可以返回指定的缓存。
type mockProxyWithCache struct {
	cache *cache.ProxyCache
}

func (m *mockProxyWithCache) GetCache() *cache.ProxyCache {
	return m.cache
}

// TestPurgeHandler_PurgeByPath_WithRealCache 测试 purgeByPath 在有真实缓存时的行为。
func TestPurgeHandler_PurgeByPath_WithRealCache(t *testing.T) {
	// 创建启用缓存的代理
	cfg := &config.ProxyConfig{
		Path:        "/api",
		LoadBalance: "round_robin",
		Timeout:     config.ProxyTimeout{Connect: 5 * time.Second},
		Cache: config.ProxyCacheConfig{
			Enabled: true,
			MaxAge:  10 * time.Second,
		},
	}
	targets := []*loadbalance.Target{{URL: "http://localhost:8080"}}
	p, err := proxy.NewProxy(cfg, targets, nil, nil)
	if err != nil {
		t.Fatalf("NewProxy() error: %v", err)
	}

	// 获取缓存并添加测试数据
	pcache := p.GetCache()
	if pcache == nil {
		t.Fatal("GetCache() should return non-nil when cache enabled")
	}

	// 添加测试缓存条目
	hashKey1 := cache.HashPathWithMethod("/api/users", "GET")
	pcache.Set(hashKey1, "GET:/api/users", []byte("test data 1"), nil, 200, time.Minute)

	hashKey2 := cache.HashPathWithMethod("/api/posts", "GET")
	pcache.Set(hashKey2, "GET:/api/posts", []byte("test data 2"), nil, 200, time.Minute)

	hashKey3 := cache.HashPathWithMethod("/api/users", "POST")
	pcache.Set(hashKey3, "POST:/api/users", []byte("test data 3"), nil, 200, time.Minute)

	// 创建带有代理的 handler
	h, err := NewPurgeHandler(&Server{
		proxies: []*proxy.Proxy{p},
	}, &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	t.Run("delete existing entry", func(t *testing.T) {
		deleted := h.PurgeByPathForTest("/api/users", "GET")
		if deleted != 1 {
			t.Errorf("expected 1 deletion, got %d", deleted)
		}
	})

	t.Run("delete different method", func(t *testing.T) {
		deleted := h.PurgeByPathForTest("/api/users", "POST")
		if deleted != 1 {
			t.Errorf("expected 1 deletion, got %d", deleted)
		}
	})

	t.Run("delete non-existing path", func(t *testing.T) {
		deleted := h.PurgeByPathForTest("/api/nonexistent", "GET")
		if deleted != 1 {
			t.Errorf("expected 1 (proxy count), got %d", deleted)
		}
	})

	t.Run("multiple proxies", func(t *testing.T) {
		// 创建第二个代理
		p2, err := proxy.NewProxy(cfg, targets, nil, nil)
		if err != nil {
			t.Fatalf("NewProxy() error: %v", err)
		}
		pcache2 := p2.GetCache()
		hashKey := cache.HashPathWithMethod("/test", "GET")
		pcache2.Set(hashKey, "GET:/test", []byte("test"), nil, 200, time.Minute)

		h2, err := NewPurgeHandler(&Server{
			proxies: []*proxy.Proxy{p, p2},
		}, &config.CacheAPIConfig{})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		deleted := h2.PurgeByPathForTest("/test", "GET")
		if deleted != 2 {
			t.Errorf("expected 2 deletions (2 proxies), got %d", deleted)
		}
	})
}

// TestPurgeHandler_PurgeByPattern_WithRealCache 测试 purgeByPattern 在有真实缓存时的行为。
func TestPurgeHandler_PurgeByPattern_WithRealCache(t *testing.T) {
	// 创建启用缓存的代理
	cfg := &config.ProxyConfig{
		Path:        "/api",
		LoadBalance: "round_robin",
		Timeout:     config.ProxyTimeout{Connect: 5 * time.Second},
		Cache: config.ProxyCacheConfig{
			Enabled: true,
			MaxAge:  10 * time.Second,
		},
	}
	targets := []*loadbalance.Target{{URL: "http://localhost:8080"}}
	p, err := proxy.NewProxy(cfg, targets, nil, nil)
	if err != nil {
		t.Fatalf("NewProxy() error: %v", err)
	}

	// 获取缓存并添加测试数据
	pcache := p.GetCache()
	if pcache == nil {
		t.Fatal("GetCache() should return non-nil when cache enabled")
	}

	// 添加多个测试缓存条目
	pcache.Set(cache.HashPathWithMethod("/api/users", "GET"), "GET:/api/users", []byte("data"), nil, 200, time.Minute)
	pcache.Set(cache.HashPathWithMethod("/api/users/1", "GET"), "GET:/api/users/1", []byte("data"), nil, 200, time.Minute)
	pcache.Set(cache.HashPathWithMethod("/api/posts", "GET"), "GET:/api/posts", []byte("data"), nil, 200, time.Minute)
	pcache.Set(cache.HashPathWithMethod("/api/posts/1", "GET"), "GET:/api/posts/1", []byte("data"), nil, 200, time.Minute)
	pcache.Set(cache.HashPathWithMethod("/api/users", "POST"), "POST:/api/users", []byte("data"), nil, 200, time.Minute)

	// 创建带有代理的 handler
	h, err := NewPurgeHandler(&Server{
		proxies: []*proxy.Proxy{p},
	}, &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	t.Run("wildcard pattern matches multiple", func(t *testing.T) {
		// 重新添加数据
		pcache.Set(cache.HashPathWithMethod("/api/users", "GET"), "GET:/api/users", []byte("data"), nil, 200, time.Minute)
		pcache.Set(cache.HashPathWithMethod("/api/users/1", "GET"), "GET:/api/users/1", []byte("data"), nil, 200, time.Minute)
		pcache.Set(cache.HashPathWithMethod("/api/posts", "GET"), "GET:/api/posts", []byte("data"), nil, 200, time.Minute)

		// 注意：OrigKey 格式为 "METHOD:/path"，所以模式需要匹配完整路径
		deleted := h.PurgeByPatternForTest("GET:/api/*", "GET")
		if deleted < 1 {
			t.Errorf("expected at least 1 deletion, got %d", deleted)
		}
	})

	t.Run("empty method matches all methods", func(t *testing.T) {
		// 重新添加数据
		pcache.Set(cache.HashPathWithMethod("/api/users", "GET"), "GET:/api/users", []byte("data"), nil, 200, time.Minute)
		pcache.Set(cache.HashPathWithMethod("/api/users", "POST"), "POST:/api/users", []byte("data"), nil, 200, time.Minute)

		// 使用 * 通配符匹配所有方法
		deleted := h.PurgeByPatternForTest("*:/api/users", "")
		if deleted < 1 {
			t.Errorf("expected at least 1 deletion (all methods), got %d", deleted)
		}
	})

	t.Run("specific method only", func(t *testing.T) {
		// 重新添加数据
		pcache.Set(cache.HashPathWithMethod("/api/users", "GET"), "GET:/api/users", []byte("data"), nil, 200, time.Minute)
		pcache.Set(cache.HashPathWithMethod("/api/users", "POST"), "POST:/api/users", []byte("data"), nil, 200, time.Minute)

		// 模式匹配 POST 方法的路径
		deleted := h.PurgeByPatternForTest("POST:/api/users", "POST")
		if deleted < 1 {
			t.Errorf("expected at least 1 deletion (POST only), got %d", deleted)
		}
	})
}

// TestPurgeHandler_PurgeByPath_WithProxyNoCache 测试代理没有缓存时的情况。
func TestPurgeHandler_PurgeByPath_WithProxyNoCache(t *testing.T) {
	// 创建禁用缓存的代理
	cfg := &config.ProxyConfig{
		Path:        "/api",
		LoadBalance: "round_robin",
		Timeout:     config.ProxyTimeout{Connect: 5 * time.Second},
		// Cache 未启用
	}
	targets := []*loadbalance.Target{{URL: "http://localhost:8080"}}
	p, err := proxy.NewProxy(cfg, targets, nil, nil)
	if err != nil {
		t.Fatalf("NewProxy() error: %v", err)
	}

	// 确认缓存为 nil
	if p.GetCache() != nil {
		t.Fatal("GetCache() should return nil when cache disabled")
	}

	// 创建带有代理的 handler
	h, err := NewPurgeHandler(&Server{
		proxies: []*proxy.Proxy{p},
	}, &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 没有缓存的代理应该返回 0
	deleted := h.PurgeByPathForTest("/api/users", "GET")
	if deleted != 0 {
		t.Errorf("expected 0 deletions for proxy without cache, got %d", deleted)
	}
}

// TestPurgeHandler_PurgeByPattern_WithProxyNoCache 测试代理没有缓存时的情况。
func TestPurgeHandler_PurgeByPattern_WithProxyNoCache(t *testing.T) {
	// 创建禁用缓存的代理
	cfg := &config.ProxyConfig{
		Path:        "/api",
		LoadBalance: "round_robin",
		Timeout:     config.ProxyTimeout{Connect: 5 * time.Second},
	}
	targets := []*loadbalance.Target{{URL: "http://localhost:8080"}}
	p, err := proxy.NewProxy(cfg, targets, nil, nil)
	if err != nil {
		t.Fatalf("NewProxy() error: %v", err)
	}

	// 创建带有代理的 handler
	h, err := NewPurgeHandler(&Server{
		proxies: []*proxy.Proxy{p},
	}, &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 没有缓存的代理应该返回 0
	deleted := h.PurgeByPatternForTest("/api/*", "GET")
	if deleted != 0 {
		t.Errorf("expected 0 deletions for proxy without cache, got %d", deleted)
	}
}

// TestPurgeHandler_PurgeByPath_WithCache 测试 purgeByPath 在有缓存时的行为。
func TestPurgeHandler_PurgeByPath_WithCache(t *testing.T) {
	t.Run("server with empty proxies", func(t *testing.T) {
		// 创建带有空 proxies 列表的 handler
		h, err := NewPurgeHandler(&Server{
			proxies: []*proxy.Proxy{},
		}, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// 空 proxies 列表应该返回 0
		deleted := h.PurgeByPathForTest("/api/users", "GET")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for empty proxies, got %d", deleted)
		}
	})

	t.Run("empty path", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// 空路径仍然会执行删除逻辑，只是哈希值为默认 GET 的哈希
		deleted := h.PurgeByPathForTest("", "")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for nil server, got %d", deleted)
		}
	})

	t.Run("path with special characters", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// 特殊字符路径
		deleted := h.PurgeByPathForTest("/api/users?id=1&name=test", "GET")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for nil server, got %d", deleted)
		}
	})

	t.Run("path with unicode", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// Unicode 路径
		deleted := h.PurgeByPathForTest("/api/用户/列表", "GET")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for nil server, got %d", deleted)
		}
	})

	t.Run("different methods", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		methods := []string{"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"}
		for _, method := range methods {
			deleted := h.PurgeByPathForTest("/api/users", method)
			if deleted != 0 {
				t.Errorf("expected 0 deletions for nil server with method %s, got %d", method, deleted)
			}
		}
	})
}

// TestPurgeHandler_PurgeByPattern_WithCache 测试 purgeByPattern 在有缓存时的行为。
func TestPurgeHandler_PurgeByPattern_WithCache(t *testing.T) {
	t.Run("empty pattern", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// 空模式
		deleted := h.PurgeByPatternForTest("", "GET")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for nil server, got %d", deleted)
		}
	})

	t.Run("wildcard pattern", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// 通配符模式
		deleted := h.PurgeByPatternForTest("/api/*", "GET")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for nil server, got %d", deleted)
		}
	})

	t.Run("double wildcard pattern", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// 双通配符模式
		deleted := h.PurgeByPatternForTest("/api/**", "GET")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for nil server, got %d", deleted)
		}
	})

	t.Run("pattern with special characters", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// 特殊字符模式
		deleted := h.PurgeByPatternForTest("/api/users?id=*", "GET")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for nil server, got %d", deleted)
		}
	})

	t.Run("exact pattern (no wildcard)", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// 精确模式（无通配符）
		deleted := h.PurgeByPatternForTest("/api/users", "GET")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for nil server, got %d", deleted)
		}
	})

	t.Run("different methods", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		methods := []string{"GET", "POST", "PUT", "DELETE", "PATCH"}
		for _, method := range methods {
			deleted := h.PurgeByPatternForTest("/api/*", method)
			if deleted != 0 {
				t.Errorf("expected 0 deletions for nil server with method %s, got %d", method, deleted)
			}
		}
	})

	t.Run("empty method matches all", func(t *testing.T) {
		h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
			Path:  "/_cache/purge",
			Allow: []string{},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// 空方法应该匹配所有条目
		deleted := h.PurgeByPatternForTest("/api/*", "")
		if deleted != 0 {
			t.Errorf("expected 0 deletions for nil server, got %d", deleted)
		}
	})
}

// TestPurgeHandler_PurgeByPath_HashConsistency 测试哈希一致性。
func TestPurgeHandler_PurgeByPath_HashConsistency(t *testing.T) {
	// 验证相同路径和方法产生相同哈希
	path := "/api/users"
	method := "GET"

	hash1 := cache.HashPathWithMethod(path, method)
	hash2 := cache.HashPathWithMethod(path, method)

	if hash1 != hash2 {
		t.Errorf("hash not consistent: %d != %d", hash1, hash2)
	}

	// 验证不同路径产生不同哈希
	hash3 := cache.HashPathWithMethod("/api/posts", method)
	if hash1 == hash3 {
		t.Error("expected different hashes for different paths")
	}

	// 验证不同方法产生不同哈希
	hash4 := cache.HashPathWithMethod(path, "POST")
	if hash1 == hash4 {
		t.Error("expected different hashes for different methods")
	}
}

// TestPurgeHandler_PurgeByPattern_PatternMatching 测试模式匹配逻辑。
func TestPurgeHandler_PurgeByPattern_PatternMatching(t *testing.T) {
	tests := []struct {
		pattern string
		path    string
		want    bool
	}{
		// 通配符结尾 - 前缀匹配
		{"/api/*", "/api/users", true},
		{"/api/*", "/api/posts", true},
		{"/api/*", "/api/users/123", true}, // * 匹配剩余所有内容
		{"/api/*", "/other/path", false},

		// 单个 * 匹配所有
		{"*", "/api/users", true},
		{"*", "/any/path", true},

		// 中间通配符
		{"/api/*/users", "/api/v1/users", true},
		{"/api/*/users", "/api/v2/users", true},
		{"/api/*/users", "/api/users", true}, // 前缀和后缀都匹配
		{"/api/*/users", "/api/v1/posts", false},

		// 精确匹配
		{"/api/users", "/api/users", true},
		{"/api/users", "/api/posts", false},

		// 空模式
		{"", "", true},
		{"", "/api", false},

		// 目录前缀匹配（以 / 结尾）
		{"/api/", "/api/users", true},
		{"/api/", "/api/users/123", true},
		{"/api/", "/other/path", false},
	}

	for _, tt := range tests {
		t.Run(tt.pattern+"_"+tt.path, func(t *testing.T) {
			got := cache.MatchPattern(tt.pattern, tt.path)
			if got != tt.want {
				t.Errorf("MatchPattern(%q, %q) = %v, want %v", tt.pattern, tt.path, got, tt.want)
			}
		})
	}
}

// TestPurgeHandler_PurgeByPath_VariousInputs 测试各种输入。
func TestPurgeHandler_PurgeByPath_VariousInputs(t *testing.T) {
	h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	tests := []struct {
		name   string
		path   string
		method string
	}{
		{"empty path and method", "", ""},
		{"empty path with method", "", "GET"},
		{"path with empty method", "/test", ""},
		{"root path", "/", "GET"},
		{"nested path", "/a/b/c/d/e", "GET"},
		{"path with trailing slash", "/api/users/", "GET"},
		{"path with query", "/api?key=value", "GET"},
		{"path with fragment", "/api#section", "GET"},
		{"path with encoded chars", "/api%2Fusers", "GET"},
		{"long path", strings.Repeat("/a", 100), "GET"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// 应该不会 panic
			deleted := h.PurgeByPathForTest(tt.path, tt.method)
			if deleted != 0 {
				t.Errorf("expected 0 deletions for nil server, got %d", deleted)
			}
		})
	}
}

// TestPurgeHandler_PurgeByPattern_VariousInputs 测试各种模式输入。
func TestPurgeHandler_PurgeByPattern_VariousInputs(t *testing.T) {
	h, err := NewPurgeHandler(nil, &config.CacheAPIConfig{
		Path:  "/_cache/purge",
		Allow: []string{},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	tests := []struct {
		name    string
		pattern string
		method  string
	}{
		{"empty pattern and method", "", ""},
		{"empty pattern with method", "", "GET"},
		{"pattern with empty method", "/api/*", ""},
		{"single wildcard only", "*", "GET"},
		{"double wildcard only", "**", "GET"},
		{"multiple single wildcards", "/api/*/users/*", "GET"},
		{"mixed wildcards", "/api/**/users/*", "GET"},
		{"wildcard at start", "*/users", "GET"},
		{"wildcard at end", "/api/*", "GET"},
		{"consecutive wildcards", "/api/**/*", "GET"},
		{"long pattern", strings.Repeat("/a*", 20), "GET"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// 应该不会 panic
			deleted := h.PurgeByPatternForTest(tt.pattern, tt.method)
			if deleted != 0 {
				t.Errorf("expected 0 deletions for nil server, got %d", deleted)
			}
		})
	}
}
