package tests

import (
	"context"
	"testing"

	"github.com/veypi/vbase/auth"
	"github.com/veypi/vbase/cfg"
)

// TestOAuthClientSecretLeak 测试 OAuth 客户端密钥泄漏
func TestOAuthClientSecretLeak(t *testing.T) {
	ensureUsers(t)

	// Grant permission to User1 to see client details
	cfg.Auth.Grant(context.Background(), User1ID, "oauth-client:*", auth.LevelRead)

	var clientID string
	var clientSecret string

	// Admin 创建 OAuth 客户端
	t.Run("Admin creates OAuth client", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/oauth/clients", map[string]any{
			"name":           "Test Client",
			"redirect_uris":  []string{"https://example.com/callback"},
			"allowed_scopes": "openid profile email",
		}, AdminToken)
		assertStatus(t, resp, 200)

		var data struct {
			ClientID     string `json:"client_id"`
			ClientSecret string `json:"client_secret"`
		}
		decodeResponse(t, resp, &data)
		clientID = data.ClientID
		clientSecret = data.ClientSecret
	})

	if clientID == "" || clientSecret == "" {
		t.Skip("Failed to create OAuth client")
	}

	// 普通用户不应该看到 client_secret
	t.Run("Regular user cannot see client secret", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/oauth/clients/"+clientID, nil, User1Token)
		assertStatus(t, resp, 200)

		var data struct {
			ClientSecret string `json:"client_secret"`
		}
		decodeResponse(t, resp, &data)

		if data.ClientSecret != "" {
			t.Errorf("Regular user should not see client_secret, got: %s", data.ClientSecret)
		}
	})

	// Admin 也不应该在 GET 请求中看到 client_secret
	t.Run("Admin GET should not reveal client secret", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/oauth/clients/"+clientID, nil, AdminToken)
		assertStatus(t, resp, 200)

		var data struct {
			ClientSecret string `json:"client_secret"`
		}
		decodeResponse(t, resp, &data)

		// client_secret 应该只在创建时返回
		if data.ClientSecret != "" {
			t.Logf("Warning: client_secret visible in GET response: %s", data.ClientSecret)
		}
	})

	// 清理
	t.Run("Cleanup", func(t *testing.T) {
		resp := doRequest(t, "DELETE", "/api/oauth/clients/"+clientID, nil, AdminToken)
		assertStatus(t, resp, 200)
	})
}

// TestOAuthClientAccessControlSecurity 测试 OAuth 客户端访问控制安全
func TestOAuthClientAccessControlSecurity(t *testing.T) {
	ensureUsers(t)

	// Grant permission to User1 to create clients
	cfg.Auth.Grant(context.Background(), User1ID, "oauth-client", auth.LevelCreate)

	var clientID string

	// User1 创建 OAuth 客户端
	t.Run("User1 creates OAuth client", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/oauth/clients", map[string]any{
			"name":           "User1 Client",
			"redirect_uris":  []string{"https://user1.com/callback"},
			"allowed_scopes": "openid profile",
		}, User1Token)
		assertStatus(t, resp, 200)

		var data struct {
			ClientID string `json:"client_id"`
		}
		decodeResponse(t, resp, &data)
		clientID = data.ClientID
	})

	if clientID == "" {
		t.Skip("Failed to create OAuth client")
	}

	// User2 不应该能修改 User1 的客户端
	t.Run("User2 cannot modify User1's client", func(t *testing.T) {
		resp := doRequest(t, "PATCH", "/api/oauth/clients/"+clientID, map[string]string{
			"name": "Hacked by User2",
		}, User2Token)
		if resp.Code == 200 {
			t.Errorf("User2 should not be able to modify User1's client, got 200")
		}
	})

	// User2 不应该能删除 User1 的客户端
	t.Run("User2 cannot delete User1's client", func(t *testing.T) {
		resp := doRequest(t, "DELETE", "/api/oauth/clients/"+clientID, nil, User2Token)
		if resp.Code == 200 {
			t.Errorf("User2 should not be able to delete User1's client, got 200")
		}
	})

	// Admin 可以修改任何客户端
	t.Run("Admin can modify any client", func(t *testing.T) {
		resp := doRequest(t, "PATCH", "/api/oauth/clients/"+clientID, map[string]string{
			"name": "Modified by Admin",
		}, AdminToken)
		assertStatus(t, resp, 200)
	})

	// 清理
	t.Run("Cleanup", func(t *testing.T) {
		resp := doRequest(t, "DELETE", "/api/oauth/clients/"+clientID, nil, AdminToken)
		assertStatus(t, resp, 200)
	})
}

// TestOAuthAuthorizeEndpoint 测试 OAuth 授权端点安全
func TestOAuthAuthorizeEndpoint(t *testing.T) {
	ensureUsers(t)

	// 测试缺少参数的授权请求
	t.Run("Authorize without client_id", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/oauth/authorize?response_type=code&redirect_uri=https://example.com/callback", nil, "")
		// 应该返回错误，因为没有 client_id
		if resp.Code == 200 {
			t.Errorf("Expected error for missing client_id, got 200")
		}
	})

	// 测试无效的 response_type
	t.Run("Authorize with invalid response_type", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/oauth/authorize?client_id=test&response_type=invalid&redirect_uri=https://example.com/callback", nil, "")
		if resp.Code == 200 {
			t.Errorf("Expected error for invalid response_type, got 200")
		}
	})
}

// TestOAuthTokenEndpoint 测试 OAuth Token 端点安全
func TestOAuthTokenEndpoint(t *testing.T) {
	ensureUsers(t)

	// 测试缺少参数的 token 请求
	t.Run("Token without grant_type", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/oauth/token", map[string]string{
			"client_id": "test",
		}, "")
		// 应该返回错误
		if resp.Code == 200 {
			t.Errorf("Expected error for missing grant_type, got 200")
		}
	})

	// 测试无效的 grant_type
	t.Run("Token with invalid grant_type", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/oauth/token", map[string]string{
			"grant_type": "invalid_grant",
			"client_id":  "test",
		}, "")
		if resp.Code == 200 {
			t.Errorf("Expected error for invalid grant_type, got 200")
		}
	})
}

// TestOAuthScopeValidation 测试 OAuth Scope 验证
func TestOAuthScopeValidation(t *testing.T) {
	ensureUsers(t)

	var clientID string

	// 创建带有特定 scope 限制的客户端
	t.Run("Create client with limited scopes", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/oauth/clients", map[string]any{
			"name":           "Limited Scope Client",
			"redirect_uris":  []string{"https://example.com/callback"},
			"allowed_scopes": "openid profile", // 只允许 openid 和 profile
		}, AdminToken)
		assertStatus(t, resp, 200)

		var data struct {
			ClientID string `json:"client_id"`
		}
		decodeResponse(t, resp, &data)
		clientID = data.ClientID
	})

	if clientID == "" {
		t.Skip("Failed to create OAuth client")
	}

	// 测试：请求超出允许范围的 scope
	t.Run("Request scope beyond allowed", func(t *testing.T) {
		// 注意：这需要实际的授权流程，这里只是测试端点行为
		resp := doRequest(t, "GET", "/api/oauth/authorize?client_id="+clientID+"&response_type=code&redirect_uri=https://example.com/callback&scope=openid profile email admin", nil, "")
		// 应该返回错误或限制 scope
		if resp.Code == 200 {
			t.Logf("Warning: Request for excessive scope returned 200, scope validation may be missing")
		}
	})

	// 清理
	t.Run("Cleanup", func(t *testing.T) {
		resp := doRequest(t, "DELETE", "/api/oauth/clients/"+clientID, nil, AdminToken)
		assertStatus(t, resp, 200)
	})
}

// TestOAuthRedirectURISecurity 测试 OAuth Redirect URI 安全
func TestOAuthRedirectURISecurity(t *testing.T) {
	ensureUsers(t)

	var clientID string

	// 创建带有特定 redirect_uri 的客户端
	t.Run("Create client with specific redirect_uri", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/oauth/clients", map[string]any{
			"name":           "URI Test Client",
			"redirect_uris":  []string{"https://trusted.example.com/callback"},
			"allowed_scopes": "openid",
		}, AdminToken)
		assertStatus(t, resp, 200)

		var data struct {
			ClientID string `json:"client_id"`
		}
		decodeResponse(t, resp, &data)
		clientID = data.ClientID
	})

	if clientID == "" {
		t.Skip("Failed to create OAuth client")
	}

	// 测试：使用不匹配的 redirect_uri
	t.Run("Authorize with mismatched redirect_uri", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/oauth/authorize?client_id="+clientID+"&response_type=code&redirect_uri=https://evil.com/callback", nil, "")
		// 应该返回错误，因为 redirect_uri 不匹配
		if resp.Code == 200 {
			t.Errorf("Expected error for mismatched redirect_uri, got 200")
		}
	})

	// 清理
	t.Run("Cleanup", func(t *testing.T) {
		resp := doRequest(t, "DELETE", "/api/oauth/clients/"+clientID, nil, AdminToken)
		assertStatus(t, resp, 200)
	})
}
