// Package security 提供访问控制功能的测试。
//
// 该文件测试访问控制模块的各项功能，包括：
//   - 访问控制器创建
//   - IP 地址检查
//   - 允许列表和拒绝列表
//   - CIDR 解析
//   - 列表更新和统计
//
// 作者：xfy
package security

import (
	"net"
	"testing"

	"github.com/valyala/fasthttp"
	"rua.plus/lolly/internal/config"
	"rua.plus/lolly/internal/utils"
)

func TestNewAccessControl(t *testing.T) {
	tests := []struct {
		cfg     *config.AccessConfig
		name    string
		wantErr bool
	}{
		{
			name:    "nil config",
			cfg:     nil,
			wantErr: true,
		},
		{
			name: "empty config",
			cfg:  &config.AccessConfig{},
		},
		{
			name: "valid allow list",
			cfg: &config.AccessConfig{
				Allow: []string{"192.168.1.0/24", "10.0.0.1"},
			},
		},
		{
			name: "valid deny list",
			cfg: &config.AccessConfig{
				Deny: []string{"192.168.2.100/32"},
			},
		},
		{
			name: "invalid CIDR",
			cfg: &config.AccessConfig{
				Allow: []string{"invalid"},
			},
			wantErr: true,
		},
		{
			name: "default allow",
			cfg: &config.AccessConfig{
				Default: "allow",
			},
		},
		{
			name: "default deny",
			cfg: &config.AccessConfig{
				Default: "deny",
			},
		},
		{
			name: "invalid default",
			cfg: &config.AccessConfig{
				Default: "invalid",
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ac, err := NewAccessControl(tt.cfg)
			if (err != nil) != tt.wantErr {
				t.Errorf("NewAccessControl() error = %v, wantErr %v", err, tt.wantErr)
			}
			if !tt.wantErr && ac == nil {
				t.Error("Expected non-nil AccessControl")
			}
		})
	}
}

func TestAccessControlCheck(t *testing.T) {
	tests := []struct {
		name     string
		cfg      *config.AccessConfig
		ip       string
		expected bool
	}{
		{
			name: "default allow",
			cfg: &config.AccessConfig{
				Default: "allow",
			},
			ip:       "192.168.1.100",
			expected: true,
		},
		{
			name: "default deny",
			cfg: &config.AccessConfig{
				Default: "deny",
			},
			ip:       "192.168.1.100",
			expected: false,
		},
		{
			name: "explicit allow",
			cfg: &config.AccessConfig{
				Allow:   []string{"192.168.1.0/24"},
				Default: "deny",
			},
			ip:       "192.168.1.100",
			expected: true,
		},
		{
			name: "not in allow list",
			cfg: &config.AccessConfig{
				Allow:   []string{"192.168.1.0/24"},
				Default: "deny",
			},
			ip:       "192.168.2.100",
			expected: false,
		},
		{
			name: "explicit deny",
			cfg: &config.AccessConfig{
				Deny:    []string{"192.168.2.100"},
				Default: "allow",
			},
			ip:       "192.168.2.100",
			expected: false,
		},
		{
			name: "deny takes precedence",
			cfg: &config.AccessConfig{
				Allow:   []string{"192.168.0.0/16"},
				Deny:    []string{"192.168.2.100"},
				Default: "deny",
			},
			ip:       "192.168.2.100",
			expected: false,
		},
		{
			name: "single IP allow",
			cfg: &config.AccessConfig{
				Allow:   []string{"10.0.0.1"},
				Default: "deny",
			},
			ip:       "10.0.0.1",
			expected: true,
		},
		{
			name: "IPv6 allow",
			cfg: &config.AccessConfig{
				Allow:   []string{"2001:db8::/32"},
				Default: "deny",
			},
			ip:       "2001:db8::1",
			expected: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ac, err := NewAccessControl(tt.cfg)
			if err != nil {
				t.Fatalf("NewAccessControl() error: %v", err)
			}

			ip := net.ParseIP(tt.ip)
			if ip == nil {
				t.Fatalf("Invalid IP: %s", tt.ip)
			}

			result := ac.Check(ip)
			if result != tt.expected {
				t.Errorf("Check(%s) = %v, expected %v", tt.ip, result, tt.expected)
			}
		})
	}
}

func TestAccessControlProcess(t *testing.T) {
	ac, err := NewAccessControl(&config.AccessConfig{
		Allow:   []string{"127.0.0.1"},
		Default: "deny",
	})
	if err != nil {
		t.Fatalf("NewAccessControl() error: %v", err)
	}

	// Create a simple handler
	nextHandler := func(ctx *fasthttp.RequestCtx) {
		_, _ = ctx.WriteString("OK")
	}

	handler := ac.Process(nextHandler)

	// Verify the handler is created correctly
	if handler == nil {
		t.Error("Process() returned nil handler")
	}
}

func TestParseCIDR(t *testing.T) {
	tests := []struct {
		name    string
		cidr    string
		wantErr bool
	}{
		{
			name: "valid IPv4 CIDR",
			cidr: "192.168.1.0/24",
		},
		{
			name: "valid IPv4 single",
			cidr: "192.168.1.1",
		},
		{
			name: "valid IPv6 CIDR",
			cidr: "2001:db8::/32",
		},
		{
			name: "valid IPv6 single",
			cidr: "2001:db8::1",
		},
		{
			name:    "invalid IP",
			cidr:    "invalid",
			wantErr: true,
		},
		{
			name:    "invalid CIDR",
			cidr:    "192.168.1.0/33",
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			network, err := utils.ParseCIDR(tt.cidr)
			if (err != nil) != tt.wantErr {
				t.Errorf("utils.ParseCIDR() error = %v, wantErr %v", err, tt.wantErr)
			}
			if !tt.wantErr && network == nil {
				t.Error("Expected non-nil network")
			}
		})
	}
}

func TestUpdateAllowList(t *testing.T) {
	ac, err := NewAccessControl(&config.AccessConfig{
		Default: "deny",
	})
	if err != nil {
		t.Fatalf("NewAccessControl() error: %v", err)
	}

	// Update allow list
	err = ac.UpdateAllowList([]string{"10.0.0.0/8"})
	if err != nil {
		t.Errorf("UpdateAllowList() error: %v", err)
	}

	// Check that IP is now allowed
	ip := net.ParseIP("10.0.0.1")
	if !ac.Check(ip) {
		t.Error("Expected IP to be allowed after update")
	}

	// Test invalid update
	err = ac.UpdateAllowList([]string{"invalid"})
	if err == nil {
		t.Error("Expected error for invalid CIDR")
	}
}

func TestUpdateDenyList(t *testing.T) {
	ac, err := NewAccessControl(&config.AccessConfig{
		Allow:   []string{"0.0.0.0/0"},
		Default: "allow",
	})
	if err != nil {
		t.Fatalf("NewAccessControl() error: %v", err)
	}

	// Update deny list
	err = ac.UpdateDenyList([]string{"192.168.2.0/24"})
	if err != nil {
		t.Errorf("UpdateDenyList() error: %v", err)
	}

	// Check that IP is now denied
	ip := net.ParseIP("192.168.2.1")
	if ac.Check(ip) {
		t.Error("Expected IP to be denied after update")
	}
}

func TestSetDefault(t *testing.T) {
	ac, err := NewAccessControl(&config.AccessConfig{
		Default: "allow",
	})
	if err != nil {
		t.Fatalf("NewAccessControl() error: %v", err)
	}

	// Change to deny
	err = ac.SetDefault("deny")
	if err != nil {
		t.Errorf("SetDefault() error: %v", err)
	}

	stats := ac.GetStats()
	if stats.Default != "deny" {
		t.Errorf("Expected default 'deny', got %s", stats.Default)
	}

	// Test invalid action
	err = ac.SetDefault("invalid")
	if err == nil {
		t.Error("Expected error for invalid action")
	}
}

func TestGetStats(t *testing.T) {
	ac, err := NewAccessControl(&config.AccessConfig{
		Allow:   []string{"192.168.1.0/24", "10.0.0.0/8"},
		Deny:    []string{"192.168.2.100"},
		Default: "deny",
	})
	if err != nil {
		t.Fatalf("NewAccessControl() error: %v", err)
	}

	stats := ac.GetStats()
	if stats.AllowCount != 2 {
		t.Errorf("Expected AllowCount 2, got %d", stats.AllowCount)
	}
	if stats.DenyCount != 1 {
		t.Errorf("Expected DenyCount 1, got %d", stats.DenyCount)
	}
	if stats.Default != "deny" {
		t.Errorf("Expected Default 'deny', got %s", stats.Default)
	}
}
