package security

import (
	"context"
	"testing"
	"time"
)

// ---- IPFilter 测试 ----

func TestIPFilter_BlacklistBasic(t *testing.T) {
	f := NewIPFilter()

	// 未加入黑名单时，IP 应该通过
	blocked, reason := f.IsBlocked("192.168.1.1")
	if blocked {
		t.Fatalf("未加入黑名单时不应被封禁，reason=%s", reason)
	}

	// 加入黑名单
	if err := f.AddToBlacklist("192.168.1.1", "测试封禁", 0); err != nil {
		t.Fatalf("AddToBlacklist 失败: %v", err)
	}

	blocked, reason = f.IsBlocked("192.168.1.1")
	if !blocked {
		t.Fatal("加入黑名单后应该被封禁")
	}
	if reason == "" {
		t.Fatal("封禁原因不应为空")
	}
	t.Logf("正确封禁，reason=%s", reason)
}

func TestIPFilter_BlacklistExpiry(t *testing.T) {
	f := NewIPFilter()

	// 加入 50ms 后过期的黑名单
	if err := f.AddToBlacklist("10.0.0.1", "临时封禁", 50*time.Millisecond); err != nil {
		t.Fatalf("AddToBlacklist 失败: %v", err)
	}

	blocked, _ := f.IsBlocked("10.0.0.1")
	if !blocked {
		t.Fatal("封禁期间应该被拦截")
	}

	// 等待过期
	time.Sleep(100 * time.Millisecond)

	blocked, _ = f.IsBlocked("10.0.0.1")
	if blocked {
		t.Fatal("过期后不应该再被封禁")
	}
	t.Log("过期解封正常")
}

func TestIPFilter_WhitelistOverridesBlacklist(t *testing.T) {
	f := NewIPFilter()

	// 同时加入黑名单和白名单
	_ = f.AddToBlacklist("172.16.0.1", "黑名单", 0)
	_ = f.AddToWhitelist("172.16.0.1", "白名单优先")

	blocked, _ := f.IsBlocked("172.16.0.1")
	if blocked {
		t.Fatal("白名单应优先于黑名单")
	}
	t.Log("白名单优先级验证通过")
}

func TestIPFilter_CIDRMatch(t *testing.T) {
	f := NewIPFilter()

	// 封禁整个 /24 段
	if err := f.AddToBlacklist("10.10.10.0/24", "封禁 C 段", 0); err != nil {
		t.Fatalf("CIDR 黑名单失败: %v", err)
	}

	cases := []struct {
		ip      string
		blocked bool
	}{
		{"10.10.10.1", true},
		{"10.10.10.254", true},
		{"10.10.11.1", false},
		{"192.168.1.1", false},
	}

	for _, tc := range cases {
		blocked, _ := f.IsBlocked(tc.ip)
		if blocked != tc.blocked {
			t.Errorf("IP %s: 期望 blocked=%v，实际=%v", tc.ip, tc.blocked, blocked)
		}
	}
}

func TestIPFilter_InvalidIP(t *testing.T) {
	f := NewIPFilter()
	err := f.AddToBlacklist("not-an-ip", "invalid", 0)
	if err == nil {
		t.Fatal("无效 IP 应返回错误")
	}
	t.Logf("无效 IP 错误: %v", err)
}

func TestIPFilter_RemoveFromBlacklist(t *testing.T) {
	f := NewIPFilter()
	_ = f.AddToBlacklist("1.2.3.4", "test", 0)
	f.RemoveFromBlacklist("1.2.3.4")

	blocked, _ := f.IsBlocked("1.2.3.4")
	if blocked {
		t.Fatal("移除黑名单后不应被封禁")
	}
}

// ---- AnomalyDetector 测试 ----

func TestAnomalyDetector_BruteForce(t *testing.T) {
	ipFilter := NewIPFilter()
	cfg := AnomalyDetectorConfig{
		MaxRecordsPerUser: 50,
		Window:            time.Minute,
		MaxFailures:       5,
		MaxDistinctIPs:    10,
		AutoBlockDuration: time.Minute,
	}
	detector := NewAnomalyDetector(cfg, ipFilter)
	ctx := context.Background()

	const userID = int64(42)
	const ip = "6.6.6.6"

	// 正常失败，未达阈值
	for i := 0; i < 4; i++ {
		events := detector.RecordLogin(ctx, userID, ip, "", "", false)
		if len(events) > 0 {
			t.Fatalf("第 %d 次失败不应触发告警", i+1)
		}
	}

	// 第 5 次失败触发暴力破解告警
	events := detector.RecordLogin(ctx, userID, ip, "", "", false)
	hasBruteForce := false
	for _, e := range events {
		if e == AnomalyBruteForce {
			hasBruteForce = true
		}
	}
	if !hasBruteForce {
		t.Fatalf("第 5 次失败应触发 brute_force 告警，实际 events=%v", events)
	}
	t.Log("暴力破解检测正常触发")

	// 验证 IP 被自动封禁
	blocked, _ := ipFilter.IsBlocked(ip)
	if !blocked {
		t.Fatal("暴力破解后该 IP 应被自动封禁")
	}
	t.Log("IP 自动封禁验证通过")
}

func TestAnomalyDetector_MultipleIPs(t *testing.T) {
	ipFilter := NewIPFilter()
	cfg := AnomalyDetectorConfig{
		MaxRecordsPerUser: 50,
		Window:            time.Minute,
		MaxFailures:       100,
		MaxDistinctIPs:    3,
		AutoBlockDuration: time.Minute,
	}
	detector := NewAnomalyDetector(cfg, ipFilter)
	ctx := context.Background()

	const userID = int64(99)
	ips := []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"}

	for _, ip := range ips {
		detector.RecordLogin(ctx, userID, ip, "", "", true)
	}

	// 第 3 个不同 IP 时触发 multiple_ip 告警
	events := detector.RecordLogin(ctx, userID, "4.4.4.4", "", "", true)
	hasMultiIP := false
	for _, e := range events {
		if e == AnomalyMultipleIP {
			hasMultiIP = true
		}
	}
	if !hasMultiIP {
		t.Fatalf("4 个不同 IP 应触发 multiple_ip 告警，实际 events=%v", events)
	}
	t.Log("多 IP 检测正常触发")
}

func TestAnomalyDetector_GetRecentLogins(t *testing.T) {
	detector := NewAnomalyDetector(DefaultAnomalyConfig, nil)
	ctx := context.Background()

	const userID = int64(1)
	for i := 0; i < 5; i++ {
		detector.RecordLogin(ctx, userID, "8.8.8.8", "", "", true)
	}

	recent := detector.GetRecentLogins(userID, 3)
	if len(recent) != 3 {
		t.Fatalf("期望获取 3 条记录，实际 %d", len(recent))
	}
}

// ---- 现有 ratelimit/validator/encryption 补充测试 ----

func TestValidateIPOrCIDR(t *testing.T) {
	cases := []struct {
		input   string
		wantErr bool
	}{
		{"192.168.1.1", false},
		{"10.0.0.0/8", false},
		{"2001:db8::1", false},
		{"not-ip", true},
		{"999.999.999.999", true},
	}
	for _, tc := range cases {
		err := validateIPOrCIDR(tc.input)
		if tc.wantErr && err == nil {
			t.Errorf("输入 %q 期望出错，但没有错误", tc.input)
		}
		if !tc.wantErr && err != nil {
			t.Errorf("输入 %q 不期望出错，但得到: %v", tc.input, err)
		}
	}
}
