package tests

import (
	"strings"
	"testing"
)

// TestSQLInjection 测试 SQL 注入防护
func TestSQLInjection(t *testing.T) {
	ensureUsers(t)

	// 测试用户名中的 SQL 注入
	t.Run("SQL Injection in username", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/auth/register", map[string]string{
			"username": "admin' OR '1'='1",
			"password": "password123",
			"email":    "sql@test.com",
		}, "")
		// 应该正常处理，不应该崩溃或返回异常
		if resp.Code == 500 {
			t.Errorf("SQL injection caused server error: %s", resp.Body.String())
		}
	})

	// 测试组织代码中的 SQL 注入
	t.Run("SQL Injection in search", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/auth/users?keyword=admin' OR '1'='1", nil, AdminToken)
		// 应该正常处理
		if resp.Code == 500 {
			t.Errorf("SQL injection in search caused server error: %s", resp.Body.String())
		}
	})
}

// TestXSSPrevention 测试 XSS 防护
func TestXSSPrevention(t *testing.T) {
	ensureUsers(t)

	xssPayload := "<script>alert('xss')</script>"

	// 测试昵称中的 XSS
	t.Run("XSS in nickname", func(t *testing.T) {
		resp := doRequest(t, "PATCH", "/api/auth/me", map[string]string{
			"nickname": xssPayload,
		}, User1Token)

		if resp.Code == 200 {
			// 检查返回的数据是否被转义
			if strings.Contains(resp.Body.String(), "<script>") {
				t.Logf("Warning: XSS payload not escaped in response: %s", resp.Body.String())
			}
		}
	})
}

// TestInputValidation 测试输入验证
func TestInputValidation(t *testing.T) {
	ensureUsers(t)

	// 测试空用户名
	t.Run("Empty username", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/auth/register", map[string]string{
			"username": "",
			"password": "password123",
			"email":    "empty@test.com",
		}, "")
		if resp.Code == 200 {
			t.Errorf("Empty username should be rejected, got 200")
		}
	})

	// 测试空密码
	t.Run("Empty password", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/auth/register", map[string]string{
			"username": "testuser_empty_pass",
			"password": "",
			"email":    "emptypass@test.com",
		}, "")
		if resp.Code == 200 {
			t.Errorf("Empty password should be rejected, got 200")
		}
	})

	// 测试超长输入
	t.Run("Overlong username", func(t *testing.T) {
		longUsername := strings.Repeat("a", 300)
		resp := doRequest(t, "POST", "/api/auth/register", map[string]string{
			"username": longUsername,
			"password": "password123",
			"email":    "long@test.com",
		}, "")
		if resp.Code == 200 {
			t.Logf("Warning: Overlong username was accepted")
		}
	})

	// 测试无效邮箱格式
	t.Run("Invalid email format", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/auth/register", map[string]string{
			"username": "testuser_invalid_email",
			"password": "password123",
			"email":    "not-an-email",
		}, "")
		if resp.Code == 200 {
			t.Logf("Warning: Invalid email format was accepted")
		}
	})
}

// TestIDOR 测试不安全的直接对象引用 (IDOR)
func TestIDOR(t *testing.T) {
	ensureUsers(t)

	// 测试：User1 尝试访问 User2 的敏感信息
	t.Run("User1 tries to access User2's data", func(t *testing.T) {
		// 尝试通过 /api/users/{id} 访问其他用户信息
		resp := doRequest(t, "GET", "/api/users/"+User2ID, nil, User1Token)
		if resp.Code == 200 {
			// 检查是否返回了敏感信息
			t.Logf("Warning: User1 can access User2's data: %s", resp.Body.String())
		}
	})

	// 测试：User1 尝试修改 User2 的信息
	t.Run("User1 tries to modify User2's data", func(t *testing.T) {
		resp := doRequest(t, "PATCH", "/api/users/"+User2ID, map[string]string{
			"nickname": "Hacked by User1",
		}, User1Token)
		if resp.Code == 200 {
			t.Errorf("User1 should not be able to modify User2's data, got 200")
		}
	})
}

// TestAuthorizationBypass 测试授权绕过
func TestAuthorizationBypass(t *testing.T) {
	ensureUsers(t)

	// 测试：尝试访问需要认证但没有提供 token 的端点
	t.Run("Access protected endpoint without token", func(t *testing.T) {
		endpoints := []struct {
			method string
			path   string
		}{
			{"GET", "/api/users"},
			{"GET", "/api/roles"},
			{"GET", "/api/auth/me"},
		}

		for _, ep := range endpoints {
			resp := doRequest(t, ep.method, ep.path, nil, "")
			if resp.Code == 200 {
				t.Errorf("%s %s should require authentication, got 200", ep.method, ep.path)
			}
		}
	})

	// 测试：使用无效 token
	t.Run("Access with invalid token", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/auth/me", nil, "invalid_token_here")
		if resp.Code == 200 {
			t.Errorf("Invalid token should be rejected, got 200")
		}
	})

	// 测试：使用过期 token（如果有办法生成）
	t.Run("Access with malformed token", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/auth/me", nil, "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.invalid")
		if resp.Code == 200 {
			t.Errorf("Malformed token should be rejected, got 200")
		}
	})
}

// TestPrivilegeEscalation 测试权限提升
func TestPrivilegeEscalation(t *testing.T) {
	ensureUsers(t)

	// 测试：普通用户尝试赋予自己 admin 角色
	t.Run("User tries to assign admin role to self", func(t *testing.T) {
		resp := doRequest(t, "PUT", "/api/users/"+User1ID+"/roles", map[string]any{
			"role_ids": []string{"admin"},
		}, User1Token)
		if resp.Code == 200 {
			t.Errorf("User should not be able to assign admin role to self, got 200")
		}
	})

	// 测试：普通用户尝试修改自己的权限
	t.Run("User tries to modify own permissions", func(t *testing.T) {
		resp := doRequest(t, "PUT", "/api/users/"+User1ID+"/permissions", map[string]any{
			"permission_ids": []string{"*:*"},
		}, User1Token)
		if resp.Code == 200 {
			t.Errorf("User should not be able to modify own permissions, got 200")
		}
	})

	// 测试：普通用户尝试创建系统角色
	t.Run("User tries to create system role", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/roles", map[string]string{
			"code":        "super_admin",
			"name":        "Super Admin",
			"description": "Trying to escalate privileges",
		}, User1Token)
		if resp.Code == 200 {
			t.Errorf("User should not be able to create roles, got 200")
		}
	})
}

// TestRateLimiting 测试速率限制（如果实现了）
func TestRateLimiting(t *testing.T) {
	ensureUsers(t)

	// 快速发送多个请求
	t.Run("Rapid requests", func(t *testing.T) {
		for i := 0; i < 10; i++ {
			resp := doRequest(t, "GET", "/api/auth/me", nil, User1Token)
			if resp.Code == 429 {
				t.Logf("Rate limiting detected after %d requests", i+1)
				return
			}
		}
		t.Logf("No rate limiting detected")
	})
}

// TestSpecialCharacters 测试特殊字符处理
func TestSpecialCharacters(t *testing.T) {
	ensureUsers(t)

	specialChars := []string{
		"test\x00null",         // null byte
		"test\nnewline",        // newline
		"test\rcarriage",       // carriage return
		"test\ttab",            // tab
		"test<script>",         // HTML tag
		"test../../etc/passwd", // path traversal
		"test%00",              // URL encoded null
		"test%2e%2e%2f",        // URL encoded path traversal
	}

	for _, char := range specialChars {
		safeChar := strings.ReplaceAll(char, " ", "_")
		if len(safeChar) > 4 {
			safeChar = safeChar[:4]
		}
		codeSuffix := safeChar
		if len(codeSuffix) > 8 {
			codeSuffix = codeSuffix[:8]
		}
		t.Run("Special char: "+safeChar+"...", func(t *testing.T) {
			resp := doRequest(t, "POST", "/api/orgs", map[string]string{
				"code": "test_" + codeSuffix,
				"name": char,
			}, User1Token)

			if resp.Code == 500 {
				t.Errorf("Special character caused server error: %s", resp.Body.String())
			}
		})
	}
}

// TestUUIDManipulation 测试 UUID 操作
func TestUUIDManipulation(t *testing.T) {
	ensureUsers(t)

	// 测试无效 UUID 格式
	t.Run("Invalid UUID format", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/users/invalid-uuid", nil, AdminToken)
		if resp.Code == 200 {
			t.Errorf("Invalid UUID should be rejected, got 200")
		}
	})

	// 测试不存在的 UUID
	t.Run("Non-existent UUID", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/users/12345678-1234-1234-1234-123456789abc", nil, AdminToken)
		if resp.Code == 200 {
			t.Errorf("Non-existent UUID should return 404, got 200")
		}
	})

	// 测试 SQL 注入风格的 UUID
	t.Run("SQL injection in UUID", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/users/' OR '1'='1", nil, AdminToken)
		if resp.Code == 200 {
			t.Errorf("SQL injection in UUID should be rejected, got 200")
		}
	})
}
