package tests

import (
	"context"
	"testing"

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

// OAuthClientResp OAuth 客户端响应
type OAuthClientResp struct {
	ID            string `json:"id"`
	ClientID      string `json:"client_id"`
	ClientSecret  string `json:"client_secret,omitempty"`
	Name          string `json:"name"`
	RedirectURIs  string `json:"redirect_uris"`
	AllowedScopes string `json:"allowed_scopes"`
}

// Test OAuth Client CRUD
func TestOAuthClientCRUD(t *testing.T) {
	ensureUsers(t)

	var clientID string // This is ClientID (string), not ID (UUID)

	// Test 1: List OAuth Clients
	t.Run("List OAuth Clients", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/oauth/clients", nil, AdminToken)
		assertStatus(t, resp, 200)

		var data struct {
			Items []OAuthClientResp `json:"items"`
		}
		decodeResponse(t, resp, &data)
		t.Logf("Total OAuth clients: %d", len(data.Items))
	})

	// Test 2: Create OAuth Client
	t.Run("Create OAuth Client", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/oauth/clients", map[string]interface{}{
			"name":           "Test OAuth Client",
			"redirect_uris":  []string{"https://example.com/callback"},
			"allowed_scopes": "openid profile email",
		}, AdminToken)
		assertStatus(t, resp, 200)

		var data OAuthClientResp
		decodeResponse(t, resp, &data)
		clientID = data.ClientID // Use ClientID, not ID
		t.Logf("Created OAuth client: %s (ID: %s)", clientID, data.ID)
	})

	if clientID == "" {
		t.Fatal("Failed to create OAuth client, skipping remaining tests")
	}

	// Test 3: Get OAuth Client Details
	t.Run("Get OAuth Client Details", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/oauth/clients/"+clientID, nil, AdminToken)
		assertStatus(t, resp, 200)

		var data OAuthClientResp
		decodeResponse(t, resp, &data)

		if data.Name != "Test OAuth Client" {
			t.Errorf("Expected name 'Test OAuth Client', got '%s'", data.Name)
		}
	})

	// Test 4: Update OAuth Client
	t.Run("Update OAuth Client", func(t *testing.T) {
		resp := doRequest(t, "PATCH", "/api/oauth/clients/"+clientID, map[string]string{
			"name": "Updated OAuth Client",
		}, AdminToken)
		assertStatus(t, resp, 200)

		// Verify update
		resp = doRequest(t, "GET", "/api/oauth/clients/"+clientID, nil, AdminToken)
		assertStatus(t, resp, 200)

		var data OAuthClientResp
		decodeResponse(t, resp, &data)

		if data.Name != "Updated OAuth Client" {
			t.Errorf("Expected name 'Updated OAuth Client', got '%s'", data.Name)
		}
	})

	// Test 5: Delete OAuth Client
	t.Run("Delete OAuth Client", func(t *testing.T) {
		resp := doRequest(t, "DELETE", "/api/oauth/clients/"+clientID, nil, AdminToken)
		assertStatus(t, resp, 200)

		// Verify deletion
		resp = doRequest(t, "GET", "/api/oauth/clients/"+clientID, nil, AdminToken)
		if resp.Code == 200 {
			t.Errorf("Expected client to be deleted, but got 200")
		} else {
			t.Logf("Client deleted successfully, got code: %d", resp.Code)
		}
	})
}

// Test regular user OAuth client access
func TestOAuthClientAccessControl(t *testing.T) {
	ensureUsers(t)

	// Grant permission to User1
	if err := cfg.Auth.Grant(context.Background(), User1ID, "oauth-client:*", auth.LevelRead); err != nil {
		t.Fatalf("Failed to grant read permission: %v", err)
	}
	if err := cfg.Auth.Grant(context.Background(), User1ID, "oauth-client", auth.LevelCreate); err != nil {
		t.Fatalf("Failed to grant create permission: %v", err)
	}

	// Regular user should be able to list OAuth clients (oauth-client:read)
	t.Run("Regular User List Clients", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/oauth/clients", nil, User1Token)
		assertStatus(t, resp, 200)
	})

	// Regular user should be able to create OAuth clients (oauth-client:create)
	t.Run("Regular User Create Client", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/oauth/clients", map[string]interface{}{
			"name":           "User OAuth Client",
			"redirect_uris":  []string{"https://example.com/callback"},
			"allowed_scopes": "openid profile email",
		}, User1Token)
		assertStatus(t, resp, 200)
	})
}
