package user_test

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"testing"

	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/yaoapp/kun/maps"
	"github.com/yaoapp/yao/openapi"
	"github.com/yaoapp/yao/openapi/tests/testutils"
)

// TestMemberList tests the GET /user/teams/:team_id/members endpoint
func TestMemberList(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register a test client for OAuth authentication
	testClient := testutils.RegisterTestClient(t, "Member List Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, testClient.ClientID)

	// Obtain access token for authenticated requests
	tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")

	// Create a test team first
	createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Member List Test Team")
	teamID := getTeamID(createdTeam)

	// Create some test members and robots for filtering tests
	testUUID := strings.ReplaceAll(uuid.New().String(), "-", "")[:8]

	// Create a robot member for member_type filtering
	robotBody := map[string]interface{}{
		"name":   "Test Robot " + testUUID,
		"email":  fmt.Sprintf("test-robot-%s@test.com", testUUID),
		"role":   "member",
		"prompt": "You are a test robot for filtering",
	}
	robotBodyBytes, _ := json.Marshal(robotBody)
	robotReq, _ := http.NewRequest("POST", serverURL+baseURL+"/user/teams/"+teamID+"/members/robots", bytes.NewBuffer(robotBodyBytes))
	robotReq.Header.Set("Content-Type", "application/json")
	robotReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
	client := &http.Client{}
	robotResp, err := client.Do(robotReq)
	if err == nil && robotResp != nil {
		robotResp.Body.Close()
		if robotResp.StatusCode != 201 {
			t.Logf("Warning: Failed to create robot member for testing (status=%d)", robotResp.StatusCode)
		}
	}

	testCases := []struct {
		name       string
		teamID     string
		query      string
		headers    map[string]string
		expectCode int
		expectMsg  string
		validateFn func(*testing.T, map[string]interface{}) // Optional validation function
	}{
		{
			"list members without authentication",
			teamID,
			"",
			map[string]string{},
			401,
			"should require authentication",
			nil,
		},
		{
			"list members with valid token",
			teamID,
			"",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should return team members with default sorting (is_owner desc, status desc, created_at desc)",
			func(t *testing.T, response map[string]interface{}) {
				// Verify default sorting: is_owner desc first, then status desc
				if data, ok := response["data"].([]interface{}); ok && len(data) > 1 {
					foundNonOwner := false
					foundActive := false

					for _, item := range data {
						member := item.(map[string]interface{})

						// Check is_owner sorting (owners first)
						isOwner := false
						if ownerVal, ok := member["is_owner"]; ok {
							switch v := ownerVal.(type) {
							case float64:
								isOwner = v == 1
							case int:
								isOwner = v == 1
							case bool:
								isOwner = v
							}
						}

						if isOwner {
							assert.False(t, foundNonOwner, "Owners should come before non-owners")
						} else {
							foundNonOwner = true
						}

						// Check status sorting (pending before active) among non-owners
						if !isOwner {
							status := member["status"].(string)
							if status == "pending" {
								assert.False(t, foundActive, "Pending members should come before active members")
							} else if status == "active" {
								foundActive = true
							}
						}
					}
				}
			},
		},
		{
			"list members with pagination",
			teamID,
			"?page=1&pagesize=10",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should handle pagination parameters",
			func(t *testing.T, response map[string]interface{}) {
				assert.Equal(t, float64(1), response["page"], "Should have correct page number")
				assert.Equal(t, float64(10), response["pagesize"], "Should have correct pagesize")
			},
		},
		{
			"list members with status filter",
			teamID,
			"?status=active",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should filter by status",
			func(t *testing.T, response map[string]interface{}) {
				if data, ok := response["data"].([]interface{}); ok {
					for _, item := range data {
						member := item.(map[string]interface{})
						assert.Equal(t, "active", member["status"], "All members should have active status")
					}
				}
			},
		},
		{
			"list members filtered by member_type user",
			teamID,
			"?member_type=user",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should filter by member_type=user",
			func(t *testing.T, response map[string]interface{}) {
				if data, ok := response["data"].([]interface{}); ok {
					for _, item := range data {
						member := item.(map[string]interface{})
						assert.Equal(t, "user", member["member_type"], "All members should be user type")
					}
				}
			},
		},
		{
			"list members filtered by member_type robot",
			teamID,
			"?member_type=robot",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should filter by member_type=robot",
			func(t *testing.T, response map[string]interface{}) {
				if data, ok := response["data"].([]interface{}); ok {
					for _, item := range data {
						member := item.(map[string]interface{})
						assert.Equal(t, "robot", member["member_type"], "All members should be robot type")
					}
				}
			},
		},
		{
			"list members filtered by role_id",
			teamID,
			"?role_id=owner:free",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should filter by role_id",
			func(t *testing.T, response map[string]interface{}) {
				if data, ok := response["data"].([]interface{}); ok {
					for _, item := range data {
						member := item.(map[string]interface{})
						assert.Equal(t, "owner:free", member["role_id"], "All members should have owner:free role")
					}
				}
			},
		},
		{
			"list members with order by created_at asc",
			teamID,
			"?order=created_at+asc",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should sort by is_owner desc, status desc, then created_at ascending",
			func(t *testing.T, response map[string]interface{}) {
				// Verify owner and status sorting priority
				if data, ok := response["data"].([]interface{}); ok && len(data) > 1 {
					foundNonOwner := false
					for _, item := range data {
						member := item.(map[string]interface{})

						isOwner := false
						if ownerVal, ok := member["is_owner"]; ok {
							switch v := ownerVal.(type) {
							case float64:
								isOwner = v == 1
							case int:
								isOwner = v == 1
							case bool:
								isOwner = v
							}
						}

						if isOwner {
							assert.False(t, foundNonOwner, "Owners should come before non-owners even with custom sorting")
						} else {
							foundNonOwner = true
						}
					}
				}
			},
		},
		{
			"list members with order by joined_at desc",
			teamID,
			"?order=joined_at+desc",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should sort by is_owner desc, status desc, then joined_at descending",
			nil,
		},
		{
			"list members with order by joined_at (default desc)",
			teamID,
			"?order=joined_at",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should sort by is_owner desc, status desc, then joined_at with default desc direction",
			nil,
		},
		{
			"list members with field selection",
			teamID,
			"?fields=id,user_id,member_type,role_id,status",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should return only selected fields",
			func(t *testing.T, response map[string]interface{}) {
				if data, ok := response["data"].([]interface{}); ok && len(data) > 0 {
					member := data[0].(map[string]interface{})
					// Should have selected fields
					assert.Contains(t, member, "id", "Should have id field")
					assert.Contains(t, member, "user_id", "Should have user_id field")
					assert.Contains(t, member, "member_type", "Should have member_type field")
					assert.Contains(t, member, "role_id", "Should have role_id field")
					assert.Contains(t, member, "status", "Should have status field")
				}
			},
		},
		{
			"list members with invalid status value",
			teamID,
			"?status=invalid_status",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should reject invalid status value",
			nil,
		},
		{
			"list members with invalid member_type value",
			teamID,
			"?member_type=invalid_type",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should reject invalid member_type value",
			nil,
		},
		{
			"list members with invalid order field",
			teamID,
			"?order=invalid_field+desc",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should reject invalid order field",
			nil,
		},
		{
			"list members with invalid order direction",
			teamID,
			"?order=created_at+invalid",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should reject invalid order direction",
			nil,
		},
		{
			"list members with combined filters",
			teamID,
			"?status=active&member_type=user&order=created_at+asc&page=1&pagesize=5",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should handle combined filters and sorting",
			func(t *testing.T, response map[string]interface{}) {
				assert.Equal(t, float64(1), response["page"], "Should have correct page number")
				assert.Equal(t, float64(5), response["pagesize"], "Should have correct pagesize")
				if data, ok := response["data"].([]interface{}); ok {
					for _, item := range data {
						member := item.(map[string]interface{})
						assert.Equal(t, "active", member["status"], "All members should have active status")
						assert.Equal(t, "user", member["member_type"], "All members should be user type")
					}
				}
			},
		},
		{
			"list members of non-existent team",
			"non-existent-team-id",
			"",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent team",
			nil,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			requestURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members" + tc.query
			req, err := http.NewRequest("GET", requestURL, nil)
			assert.NoError(t, err, "Should create HTTP request")

			// Add headers
			for key, value := range tc.headers {
				req.Header.Set(key, value)
			}

			httpClient := &http.Client{}
			resp, err := httpClient.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				if resp.StatusCode == 200 {
					// Parse response as pagination result
					var response map[string]interface{}
					err = json.Unmarshal(body, &response)
					assert.NoError(t, err, "Should parse JSON response")

					// Check pagination structure
					assert.Contains(t, response, "data", "Should have data array")
					assert.Contains(t, response, "total", "Should have total count")
					assert.Contains(t, response, "page", "Should have page number")
					assert.Contains(t, response, "pagesize", "Should have pagesize")

					// Run custom validation if provided
					if tc.validateFn != nil {
						tc.validateFn(t, response)
					}
				}

				t.Logf("Member list test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// TestMemberGet tests the GET /user/teams/:team_id/members/:member_id endpoint
func TestMemberGet(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register a test client for OAuth authentication
	testClient := testutils.RegisterTestClient(t, "Member Get Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, testClient.ClientID)

	// Obtain access token for authenticated requests
	tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")

	// Create a test team and get owner member ID
	createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Member Get Test Team")
	teamID := getTeamID(createdTeam)

	// Get member list to find the owner member ID
	ownerMemberID := getOwnerMemberID(t, serverURL, baseURL, teamID, tokenInfo.AccessToken)

	testCases := []struct {
		name       string
		teamID     string
		memberID   string
		headers    map[string]string
		expectCode int
		expectMsg  string
	}{
		{
			"get member without authentication",
			teamID,
			ownerMemberID,
			map[string]string{},
			401,
			"should require authentication",
		},
		{
			"get existing member",
			teamID,
			ownerMemberID,
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should return member details",
		},
		{
			"get non-existent member",
			teamID,
			"999999",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent member",
		},
		{
			"get member from non-existent team",
			"non-existent-team-id",
			ownerMemberID,
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent team",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			requestURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members/" + tc.memberID
			req, err := http.NewRequest("GET", requestURL, nil)
			assert.NoError(t, err, "Should create HTTP request")

			// Add headers
			for key, value := range tc.headers {
				req.Header.Set(key, value)
			}

			client := &http.Client{}
			resp, err := client.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				if resp.StatusCode == 200 {
					// Parse response as member object
					var member map[string]interface{}
					err = json.Unmarshal(body, &member)
					assert.NoError(t, err, "Should parse JSON response")

					// Verify member structure
					assert.Contains(t, member, "id", "Should have member ID")
					assert.Contains(t, member, "team_id", "Should have team_id")
					assert.Contains(t, member, "user_id", "Should have user_id")
					assert.Contains(t, member, "role_id", "Should have role_id")
					assert.Contains(t, member, "status", "Should have status")
					assert.Contains(t, member, "created_at", "Should have created_at")
					assert.Contains(t, member, "updated_at", "Should have updated_at")

					// Verify values
					assert.Equal(t, teamID, member["team_id"], "Should have correct team_id")
					assert.Equal(t, tokenInfo.UserID, member["user_id"], "Should have correct user_id")
				}

				t.Logf("Member get test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// TestMemberUpdate tests the PUT /user/teams/:team_id/members/:member_id endpoint
func TestMemberUpdate(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register a test client for OAuth authentication
	testClient := testutils.RegisterTestClient(t, "Member Update Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, testClient.ClientID)

	// Obtain access token for authenticated requests
	tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")

	testCases := []struct {
		name       string
		setupFunc  func() (string, string) // Returns (teamID, memberID)
		body       map[string]interface{}
		headers    map[string]string
		expectCode int
		expectMsg  string
	}{
		{
			"update member without authentication",
			func() (string, string) {
				team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 1")
				teamID := getTeamID(team)
				memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-1")
				return teamID, memberID
			},
			map[string]interface{}{
				"role_id": "admin",
			},
			map[string]string{},
			401,
			"should require authentication",
		},
		{
			"update member role",
			func() (string, string) {
				team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 2")
				teamID := getTeamID(team)
				memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-2")
				return teamID, memberID
			},
			map[string]interface{}{
				"role_id": "admin",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update member role",
		},
		{
			"update member status",
			func() (string, string) {
				team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 3")
				teamID := getTeamID(team)
				memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-3")
				return teamID, memberID
			},
			map[string]interface{}{
				"status": "inactive",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update member status",
		},
		{
			"update non-existent member",
			func() (string, string) {
				team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 5")
				teamID := getTeamID(team)
				return teamID, "999999"
			},
			map[string]interface{}{
				"role_id": "admin",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent member",
		},
		{
			"update member in non-existent team",
			func() (string, string) {
				team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 6")
				teamID := getTeamID(team)
				memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-5")
				return "non-existent-team-id", memberID
			},
			map[string]interface{}{
				"role_id": "admin",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent team",
		},
		{
			"update member with invalid JSON",
			func() (string, string) {
				team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 7")
				teamID := getTeamID(team)
				memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-6")
				return teamID, memberID
			},
			nil, // Will send invalid JSON
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should handle invalid JSON",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			teamID, memberID := tc.setupFunc()
			requestURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID

			var req *http.Request
			var err error

			if tc.body == nil {
				// Send invalid JSON for invalid JSON test case
				req, err = http.NewRequest("PUT", requestURL, bytes.NewBufferString("invalid json"))
			} else {
				bodyBytes, _ := json.Marshal(tc.body)
				req, err = http.NewRequest("PUT", requestURL, bytes.NewBuffer(bodyBytes))
			}
			assert.NoError(t, err, "Should create HTTP request")

			req.Header.Set("Content-Type", "application/json")

			// Add headers
			for key, value := range tc.headers {
				req.Header.Set(key, value)
			}

			client := &http.Client{}
			resp, err := client.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				if resp.StatusCode == 200 {
					// Parse response as success message
					var response map[string]interface{}
					err = json.Unmarshal(body, &response)
					assert.NoError(t, err, "Should parse JSON response")

					assert.Contains(t, response, "message", "Should have success message")
					assert.Equal(t, "Member updated successfully", response["message"], "Should have correct success message")
				}

				t.Logf("Member update test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// TestMemberDelete tests the DELETE /user/teams/:team_id/members/:member_id endpoint
func TestMemberDelete(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register a test client for OAuth authentication
	testClient := testutils.RegisterTestClient(t, "Member Delete Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, testClient.ClientID)

	// Obtain access token for authenticated requests
	tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")

	// Create teams and members for testing deletion
	createMemberForDeletion := func(name string) (string, string) {
		team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Delete Test Team "+name)
		teamID := getTeamID(team)
		memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-delete-user-"+name)
		return teamID, memberID
	}

	testCases := []struct {
		name       string
		setupFunc  func() (string, string) // Returns (teamID, memberID)
		headers    map[string]string
		expectCode int
		expectMsg  string
	}{
		{
			"delete member without authentication",
			func() (string, string) { return createMemberForDeletion("1") },
			map[string]string{},
			401,
			"should require authentication",
		},
		{
			"delete existing member",
			func() (string, string) { return createMemberForDeletion("2") },
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should delete member successfully",
		},
		{
			"delete non-existent member",
			func() (string, string) {
				team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Delete Test Team 3")
				return getTeamID(team), "999999"
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent member",
		},
		{
			"delete member from non-existent team",
			func() (string, string) {
				_, memberID := createMemberForDeletion("4")
				return "non-existent-team-id", memberID
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent team",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			teamID, memberID := tc.setupFunc()
			requestURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID

			req, err := http.NewRequest("DELETE", requestURL, nil)
			assert.NoError(t, err, "Should create HTTP request")

			// Add headers
			for key, value := range tc.headers {
				req.Header.Set(key, value)
			}

			client := &http.Client{}
			resp, err := client.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				if resp.StatusCode == 200 {
					// Parse response as success message
					var response map[string]interface{}
					err = json.Unmarshal(body, &response)
					assert.NoError(t, err, "Should parse JSON response")

					assert.Contains(t, response, "message", "Should have success message")
					assert.Equal(t, "Member removed successfully", response["message"], "Should have correct success message")
				}

				t.Logf("Member delete test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// TestMemberPermissionVerification tests permission verification for member operations
func TestMemberPermissionVerification(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register test clients for different users
	ownerClient := testutils.RegisterTestClient(t, "Owner Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, ownerClient.ClientID)

	nonOwnerClient := testutils.RegisterTestClient(t, "Non-Owner Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, nonOwnerClient.ClientID)

	// Obtain access tokens
	ownerToken := testutils.ObtainAccessToken(t, serverURL, ownerClient.ClientID, ownerClient.ClientSecret, "https://localhost/callback", "openid profile")
	nonOwnerToken := testutils.ObtainAccessToken(t, serverURL, nonOwnerClient.ClientID, nonOwnerClient.ClientSecret, "https://localhost/callback", "openid profile")

	// Create a team with owner
	createdTeam := createTestTeam(t, serverURL, baseURL, ownerToken.AccessToken, "Permission Test Team")
	teamID := getTeamID(createdTeam)

	// Add non-owner as a member
	memberID := createTestMember(t, serverURL, baseURL, teamID, ownerToken.AccessToken, nonOwnerToken.UserID)

	testCases := []struct {
		name       string
		endpoint   string
		method     string
		token      string
		expectCode int
		expectMsg  string
	}{
		{
			"owner can list members",
			"/user/teams/" + teamID + "/members",
			"GET",
			ownerToken.AccessToken,
			200,
			"owner should be able to list members",
		},
		{
			"member can list members",
			"/user/teams/" + teamID + "/members",
			"GET",
			nonOwnerToken.AccessToken,
			200,
			"member should be able to list members",
		},
		{
			"owner can get member details",
			"/user/teams/" + teamID + "/members/" + memberID,
			"GET",
			ownerToken.AccessToken,
			200,
			"owner should be able to get member details",
		},
		{
			"member can get member details",
			"/user/teams/" + teamID + "/members/" + memberID,
			"GET",
			nonOwnerToken.AccessToken,
			200,
			"member should be able to get member details",
		},
		{
			"owner can update members",
			"/user/teams/" + teamID + "/members/" + memberID,
			"PUT",
			ownerToken.AccessToken,
			200,
			"owner should be able to update members",
		},
		{
			"member cannot update members",
			"/user/teams/" + teamID + "/members/" + memberID,
			"PUT",
			nonOwnerToken.AccessToken,
			403,
			"member should not be able to update members",
		},
		{
			"owner can delete members",
			"/user/teams/" + teamID + "/members/" + memberID,
			"DELETE",
			ownerToken.AccessToken,
			200,
			"owner should be able to delete members",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			requestURL := serverURL + baseURL + tc.endpoint

			var req *http.Request
			var err error

			// Create request body for POST/PUT methods
			if tc.method == "POST" {
				body := map[string]interface{}{
					"user_id": "test-permission-user",
					"role_id": "member",
				}
				bodyBytes, _ := json.Marshal(body)
				req, err = http.NewRequest(tc.method, requestURL, bytes.NewBuffer(bodyBytes))
				req.Header.Set("Content-Type", "application/json")
			} else if tc.method == "PUT" {
				body := map[string]interface{}{
					"role_id": "admin",
				}
				bodyBytes, _ := json.Marshal(body)
				req, err = http.NewRequest(tc.method, requestURL, bytes.NewBuffer(bodyBytes))
				req.Header.Set("Content-Type", "application/json")
			} else {
				req, err = http.NewRequest(tc.method, requestURL, nil)
			}

			assert.NoError(t, err, "Should create HTTP request")

			req.Header.Set("Authorization", "Bearer "+tc.token)

			client := &http.Client{}
			resp, err := client.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				t.Logf("Permission test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// Helper functions

// createTestTeam creates a team for testing and returns the team data
func createTestTeam(t *testing.T, serverURL, baseURL, accessToken, teamName string) map[string]interface{} {
	createTeamBody := map[string]interface{}{
		"name":        teamName,
		"description": "Team created for testing purposes",
		"role_id":     "system:root", // Use system:root role which includes all scopes
	}

	bodyBytes, err := json.Marshal(createTeamBody)
	assert.NoError(t, err, "Should marshal team creation body")

	req, err := http.NewRequest("POST", serverURL+baseURL+"/user/teams", bytes.NewBuffer(bodyBytes))
	assert.NoError(t, err, "Should create team creation request")

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+accessToken)

	client := &http.Client{}
	resp, err := client.Do(req)
	assert.NoError(t, err, "Should send team creation request")
	defer resp.Body.Close()

	assert.Equal(t, 201, resp.StatusCode, "Should create team successfully")

	body, err := io.ReadAll(resp.Body)
	assert.NoError(t, err, "Should read team creation response")

	var team map[string]interface{}
	err = json.Unmarshal(body, &team)
	assert.NoError(t, err, "Should parse team creation response")

	return team
}

// createTestMember creates a member for testing using provider directly (no API call).
// This is the recommended approach since direct member creation endpoint was removed.
// Members should normally be added via invitation flow or robot creation endpoint.
// Returns the member_id (global unique identifier).
func createTestMember(t *testing.T, serverURL, baseURL, teamID, accessToken, userID string) string {
	// Get user provider for direct database operations
	provider := testutils.GetUserProvider(t)
	ctx := context.Background()

	// Create member data using maps.MapStrAny (required by UserProvider interface)
	memberData := maps.MapStrAny{
		"team_id":     teamID,
		"user_id":     userID,
		"member_type": "user",
		"role_id":     "team:member",
		"status":      "active",
	}

	// Create member directly in database
	memberID, err := provider.CreateMember(ctx, memberData)
	assert.NoError(t, err, "Should create member in database")
	assert.NotEmpty(t, memberID, "Member ID should not be empty")

	t.Logf("Created test member directly in database: user_id=%s, member_id=%s, team_id=%s", userID, memberID, teamID)

	// Return member_id (global unique identifier used in API)
	return memberID
}

// getOwnerMemberID gets the member_id of the team owner (global unique identifier)
func getOwnerMemberID(t *testing.T, serverURL, baseURL, teamID, accessToken string) string {
	req, err := http.NewRequest("GET", serverURL+baseURL+"/user/teams/"+teamID+"/members", nil)
	assert.NoError(t, err, "Should create member list request")

	req.Header.Set("Authorization", "Bearer "+accessToken)

	client := &http.Client{}
	resp, err := client.Do(req)
	assert.NoError(t, err, "Should send member list request")
	defer resp.Body.Close()

	assert.Equal(t, 200, resp.StatusCode, "Should get members successfully")

	body, err := io.ReadAll(resp.Body)
	assert.NoError(t, err, "Should read member list response")

	var response map[string]interface{}
	err = json.Unmarshal(body, &response)
	assert.NoError(t, err, "Should parse member list response")

	data, ok := response["data"].([]interface{})
	assert.True(t, ok, "Should have data array")
	assert.Greater(t, len(data), 0, "Should have at least one member")

	// Find the owner member and return their member_id
	for _, item := range data {
		member := item.(map[string]interface{})
		if role, ok := member["role_id"].(string); ok && strings.HasPrefix(role, "owner") {
			memberID, ok := member["member_id"].(string)
			if !ok {
				t.Fatal("Owner member missing member_id")
			}
			return memberID
		}
	}

	t.Fatal("Could not find owner member")
	return ""
}

// TestMemberCreateRobot tests the POST /user/teams/:team_id/members/robots endpoint
func TestMemberCreateRobot(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register a test client for OAuth authentication
	testClient := testutils.RegisterTestClient(t, "Robot Member Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, testClient.ClientID)

	// Obtain access token with root permissions (required for creating robot members)
	tokenInfo := testutils.ObtainAccessTokenWithRootPermission(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")

	// Use UUID to ensure unique team name
	testUUID := strings.ReplaceAll(uuid.New().String(), "-", "")[:8]

	// Create a test team
	createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Robot Member Test Team "+testUUID)
	teamID := getTeamID(createdTeam)

	testCases := []struct {
		name       string
		teamID     string
		body       map[string]interface{}
		headers    map[string]string
		expectCode int
		expectMsg  string
	}{
		{
			"create robot without authentication",
			teamID,
			map[string]interface{}{
				"name":   "Test Robot",
				"email":  "robot@test.com",
				"role":   "member",
				"prompt": "You are a helpful assistant",
			},
			map[string]string{},
			401,
			"should require authentication",
		},
		{
			"create robot with all fields",
			teamID,
			map[string]interface{}{
				"name":               "AI Assistant Full",
				"avatar":             fmt.Sprintf("https://example.com/avatars/ai-full-%s.png", testUUID),
				"email":              fmt.Sprintf("ai-full-%s@test.com", testUUID),
				"robot_email":        fmt.Sprintf("robot-full-%s@robot.test.com", testUUID),
				"authorized_senders": []string{"user1@test.com", "user2@test.com"},
				"email_filter_rules": []string{".*@company\\.com", ".*@partner\\.com"},
				"bio":                "A comprehensive AI assistant",
				"role":               "member",
				"report_to":          tokenInfo.UserID,
				"prompt":             "You are a helpful AI assistant with full capabilities",
				"llm":                "gpt-4",
				"agents":             []string{"data-analyst", "code-reviewer"},
				"mcp_tools":          []string{"filesystem", "database"},
				"autonomous_mode":    "enabled",
				"cost_limit":         100.50,
				"workspace":          "ws-test-create",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			201,
			"should create robot with all fields successfully",
		},
		{
			"create robot with required fields only",
			teamID,
			map[string]interface{}{
				"name":        "AI Assistant Min",
				"robot_email": fmt.Sprintf("ai-min-%s@test.com", testUUID),
				"role":        "member",
				"prompt":      "You are a basic assistant",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			201,
			"should create robot with required fields only",
		},
		{
			"create robot with autonomous_mode variations",
			teamID,
			map[string]interface{}{
				"name":            "AI Assistant Auto",
				"robot_email":     fmt.Sprintf("ai-auto-%s@test.com", testUUID),
				"role":            "member",
				"prompt":          "You are an autonomous assistant",
				"autonomous_mode": "1", // Test numeric string
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			201,
			"should handle autonomous_mode=1",
		},
		{
			"create robot with disabled autonomous_mode",
			teamID,
			map[string]interface{}{
				"name":            "AI Assistant Manual",
				"robot_email":     fmt.Sprintf("ai-manual-%s@test.com", testUUID),
				"role":            "member",
				"prompt":          "You are a manual assistant",
				"autonomous_mode": "disabled",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			201,
			"should handle autonomous_mode=disabled",
		},
		{
			"create robot without name",
			teamID,
			map[string]interface{}{
				"robot_email": "no-name@test.com",
				"role":        "member",
				"prompt":      "You are an assistant",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should require name",
		},
		{
			"create robot without robot_email",
			teamID,
			map[string]interface{}{
				"name":   "No Robot Email Robot",
				"role":   "member",
				"prompt": "You are an assistant",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should require robot_email",
		},
		{
			"create robot without role",
			teamID,
			map[string]interface{}{
				"name":        "No Role Robot",
				"robot_email": "no-role@test.com",
				"prompt":      "You are an assistant",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should require role",
		},
		{
			"create robot without prompt",
			teamID,
			map[string]interface{}{
				"name":        "No Prompt Robot",
				"robot_email": "no-prompt@test.com",
				"role":        "member",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should require prompt",
		},
		{
			"create robot with duplicate robot_email",
			teamID,
			map[string]interface{}{
				"name":        "Duplicate Robot Email Robot",
				"email":       fmt.Sprintf("duplicate-robot-%s@test.com", testUUID),  // Different email
				"robot_email": fmt.Sprintf("robot-full-%s@robot.test.com", testUUID), // Same robot_email as first successful case
				"role":        "member",
				"prompt":      "You are an assistant",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			409,
			"should reject duplicate robot_email globally",
		},
		{
			"create robot in non-existent team",
			"non-existent-team-id",
			map[string]interface{}{
				"name":        "Robot in Void",
				"robot_email": "void@test.com",
				"role":        "member",
				"prompt":      "You are lost",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent team",
		},
		{
			"create robot with invalid JSON",
			teamID,
			nil, // Will send invalid JSON
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should handle invalid JSON",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			requestURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members/robots"

			var req *http.Request
			var err error

			if tc.body == nil {
				// Send invalid JSON for invalid JSON test case
				req, err = http.NewRequest("POST", requestURL, bytes.NewBufferString("invalid json"))
			} else {
				bodyBytes, _ := json.Marshal(tc.body)
				req, err = http.NewRequest("POST", requestURL, bytes.NewBuffer(bodyBytes))
			}
			assert.NoError(t, err, "Should create HTTP request")

			req.Header.Set("Content-Type", "application/json")

			// Add headers
			for key, value := range tc.headers {
				req.Header.Set(key, value)
			}

			client := &http.Client{}
			resp, err := client.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				if resp.StatusCode == 201 {
					// Parse response as created member
					var response map[string]interface{}
					err = json.Unmarshal(body, &response)
					assert.NoError(t, err, "Should parse JSON response")

					// Verify response structure
					assert.Contains(t, response, "member_id", "Should have member_id")
					assert.NotEmpty(t, response["member_id"], "Member ID should not be empty")

					// Verify the member was created with correct type
					memberID := toString(response["member_id"])
					getMemberURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members/" + memberID
					getReq, _ := http.NewRequest("GET", getMemberURL, nil)
					getReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)

					getResp, err := client.Do(getReq)
					if err == nil && getResp != nil {
						defer getResp.Body.Close()
						if getResp.StatusCode == 200 {
							var member map[string]interface{}
							getBody, _ := io.ReadAll(getResp.Body)
							json.Unmarshal(getBody, &member)

							// Verify robot member fields
							assert.Equal(t, "robot", member["member_type"], "Should be robot member type")
							if tc.body["name"] != nil {
								assert.Equal(t, tc.body["name"], member["display_name"], "Should have correct display_name")
							}
							if tc.body["email"] != nil {
								assert.Equal(t, tc.body["email"], member["email"], "Should have correct email")
							}
							if tc.body["prompt"] != nil {
								assert.Equal(t, tc.body["prompt"], member["system_prompt"], "Should have correct system_prompt")
							}
							if tc.body["workspace"] != nil {
								assert.Equal(t, "ws-test-create", member["workspace"], "Should have correct workspace")
							}
						}
					}
				}

				t.Logf("Robot member create test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// toString converts interface{} to string for test assertions
func toString(v interface{}) string {
	switch val := v.(type) {
	case string:
		return val
	case float64:
		return fmt.Sprintf("%.0f", val)
	case int:
		return fmt.Sprintf("%d", val)
	case int64:
		return fmt.Sprintf("%d", val)
	default:
		return fmt.Sprintf("%v", val)
	}
}

// TestMemberCheckRobotEmail tests the GET /user/teams/:team_id/members/check-robot-email endpoint
func TestMemberCheckRobotEmail(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register a test client for OAuth authentication
	testClient := testutils.RegisterTestClient(t, "Member Check Robot Email Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, testClient.ClientID)

	// Obtain access token for authenticated requests
	tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")

	// Use UUID to ensure unique test data
	testUUID := strings.ReplaceAll(uuid.New().String(), "-", "")[:8]

	// Create a test team
	createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Robot Email Check Test Team "+testUUID)
	teamID := getTeamID(createdTeam)

	// Create a robot member with a known robot_email (globally unique)
	existingRobotEmail := fmt.Sprintf("existing-robot-%s@robot.test.com", testUUID)
	robotBody := map[string]interface{}{
		"name":        "Existing Robot",
		"email":       fmt.Sprintf("display-%s@test.com", testUUID), // Display email (can be non-unique)
		"robot_email": existingRobotEmail,                           // Globally unique robot email
		"role":        "member",
		"prompt":      "You are a test robot",
	}
	robotBodyBytes, _ := json.Marshal(robotBody)
	robotReq, _ := http.NewRequest("POST", serverURL+baseURL+"/user/teams/"+teamID+"/members/robots", bytes.NewBuffer(robotBodyBytes))
	robotReq.Header.Set("Content-Type", "application/json")
	robotReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
	client := &http.Client{}
	robotResp, err := client.Do(robotReq)
	assert.NoError(t, err)
	if robotResp != nil {
		robotResp.Body.Close()
		assert.Equal(t, 201, robotResp.StatusCode, "Should create robot member successfully")
	}

	testCases := []struct {
		name         string
		teamID       string
		robotEmail   string
		headers      map[string]string
		expectCode   int
		expectExists bool
		expectMsg    string
	}{
		{
			"check robot email without authentication",
			teamID,
			existingRobotEmail,
			map[string]string{},
			401,
			false,
			"should require authentication",
		},
		{
			"check existing robot email",
			teamID,
			existingRobotEmail,
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			true,
			"should return exists=true for existing robot email",
		},
		{
			"check non-existing robot email",
			teamID,
			fmt.Sprintf("nonexistent-%s@robot.test.com", testUUID),
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			false,
			"should return exists=false for non-existing robot email",
		},
		{
			"check robot email without robot_email parameter",
			teamID,
			"",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			false,
			"should require robot_email parameter",
		},
		{
			"check robot email in non-existent team",
			"non-existent-team-id",
			"test@robot.example.com",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			false,
			"should return not found for non-existent team",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			requestURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members/check-robot-email"
			if tc.robotEmail != "" {
				requestURL += "?robot_email=" + tc.robotEmail
			}

			req, err := http.NewRequest("GET", requestURL, nil)
			assert.NoError(t, err, "Should create HTTP request")

			// Add headers
			for key, value := range tc.headers {
				req.Header.Set(key, value)
			}

			resp, err := client.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				if resp.StatusCode == 200 {
					// Parse response
					var response map[string]interface{}
					err = json.Unmarshal(body, &response)
					assert.NoError(t, err, "Should parse JSON response")

					// Verify response structure (global check, no team_id in response)
					assert.Contains(t, response, "exists", "Should have exists field")
					assert.Contains(t, response, "robot_email", "Should have robot_email field")

					// Verify values
					assert.Equal(t, tc.expectExists, response["exists"], "Should have correct exists value")
					assert.Equal(t, tc.robotEmail, response["robot_email"], "Should have correct robot_email")
				}

				t.Logf("Member check email test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// TestMemberUpdateRobot tests the PUT /user/teams/:team_id/members/robots/:member_id endpoint
func TestMemberUpdateRobot(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register a test client for OAuth authentication
	testClient := testutils.RegisterTestClient(t, "Robot Member Update Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, testClient.ClientID)

	// Obtain access token with root permissions (required for robot operations)
	tokenInfo := testutils.ObtainAccessTokenWithRootPermission(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")

	// Use UUID to ensure unique test data
	testUUID := strings.ReplaceAll(uuid.New().String(), "-", "")[:8]

	// Create a test team
	createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Robot Update Test Team "+testUUID)
	teamID := getTeamID(createdTeam)

	// Helper function to create a robot member for testing
	createTestRobot := func(suffix string) (string, string) {
		robotEmail := fmt.Sprintf("test-robot-%s-%s@robot.test.com", testUUID, suffix)
		robotBody := map[string]interface{}{
			"name":            "Test Robot " + suffix,
			"robot_email":     robotEmail,
			"email":           fmt.Sprintf("display-%s-%s@test.com", testUUID, suffix),
			"role":            "member",
			"prompt":          "Original prompt for " + suffix,
			"llm":             "gpt-3.5-turbo",
			"autonomous_mode": "disabled",
			"cost_limit":      50.0,
			"workspace":       "ws-initial",
		}
		robotBodyBytes, _ := json.Marshal(robotBody)
		robotReq, _ := http.NewRequest("POST", serverURL+baseURL+"/user/teams/"+teamID+"/members/robots", bytes.NewBuffer(robotBodyBytes))
		robotReq.Header.Set("Content-Type", "application/json")
		robotReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
		client := &http.Client{}
		robotResp, err := client.Do(robotReq)
		assert.NoError(t, err)
		if robotResp != nil {
			defer robotResp.Body.Close()
			assert.Equal(t, 201, robotResp.StatusCode, "Should create robot member successfully")
			body, _ := io.ReadAll(robotResp.Body)
			var response map[string]interface{}
			json.Unmarshal(body, &response)
			return toString(response["member_id"]), robotEmail
		}
		return "", ""
	}

	testCases := []struct {
		name       string
		setupFunc  func() (string, string) // Returns (memberID, originalRobotEmail)
		body       map[string]interface{}
		headers    map[string]string
		expectCode int
		expectMsg  string
		validateFn func(*testing.T, string) // Optional validation function with memberID
	}{
		{
			"update robot without authentication",
			func() (string, string) { return createTestRobot("1") },
			map[string]interface{}{
				"name": "Updated Name",
			},
			map[string]string{},
			401,
			"should require authentication",
			nil,
		},
		{
			"update robot with all fields",
			func() (string, string) { return createTestRobot("2") },
			map[string]interface{}{
				"name":               "Updated Robot Full",
				"avatar":             fmt.Sprintf("https://example.com/avatars/full-%s.png", testUUID),
				"email":              fmt.Sprintf("updated-display-%s@test.com", testUUID),
				"robot_email":        fmt.Sprintf("updated-robot-%s@robot.test.com", testUUID),
				"bio":                "Updated comprehensive description",
				"role":               "admin",
				"report_to":          tokenInfo.UserID,
				"prompt":             "Updated system prompt",
				"llm":                "gpt-4",
				"agents":             []string{"agent1", "agent2"},
				"mcp_tools":          []string{"tool1", "tool2"},
				"authorized_senders": []string{"admin@test.com"},
				"email_filter_rules": []string{".*@test\\.com$"},
				"autonomous_mode":    "enabled",
				"cost_limit":         100.0,
				"status":             "active",
				"robot_status":       "working",
				"workspace":          "ws-updated",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update robot with all fields successfully",
			func(t *testing.T, memberID string) {
				// Verify the update
				getMemberURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
				getReq, _ := http.NewRequest("GET", getMemberURL, nil)
				getReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
				client := &http.Client{}
				getResp, err := client.Do(getReq)
				assert.NoError(t, err)
				if getResp != nil {
					defer getResp.Body.Close()
					if getResp.StatusCode == 200 {
						var member map[string]interface{}
						body, _ := io.ReadAll(getResp.Body)
						json.Unmarshal(body, &member)
						assert.Equal(t, "Updated Robot Full", member["display_name"])
						assert.Equal(t, fmt.Sprintf("https://example.com/avatars/full-%s.png", testUUID), member["avatar"])
						assert.Equal(t, "Updated system prompt", member["system_prompt"])
						assert.Equal(t, "gpt-4", member["language_model"])
						assert.Equal(t, "ws-updated", member["workspace"], "Should have correct workspace")
					}
				}
			},
		},
		{
			"update robot with partial fields",
			func() (string, string) { return createTestRobot("3") },
			map[string]interface{}{
				"name":   "Partially Updated Robot",
				"prompt": "Partially updated prompt",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update robot with partial fields",
			func(t *testing.T, memberID string) {
				getMemberURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
				getReq, _ := http.NewRequest("GET", getMemberURL, nil)
				getReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
				client := &http.Client{}
				getResp, err := client.Do(getReq)
				assert.NoError(t, err)
				if getResp != nil {
					defer getResp.Body.Close()
					if getResp.StatusCode == 200 {
						var member map[string]interface{}
						body, _ := io.ReadAll(getResp.Body)
						json.Unmarshal(body, &member)
						assert.Equal(t, "Partially Updated Robot", member["display_name"])
						assert.Equal(t, "Partially updated prompt", member["system_prompt"])
						// Original fields should remain
						assert.Equal(t, "gpt-3.5-turbo", member["language_model"])
					}
				}
			},
		},
		{
			"update robot_email to new unique email",
			func() (string, string) { return createTestRobot("4") },
			map[string]interface{}{
				"robot_email": fmt.Sprintf("new-unique-%s@robot.test.com", testUUID),
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update robot_email to new unique email",
			func(t *testing.T, memberID string) {
				getMemberURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
				getReq, _ := http.NewRequest("GET", getMemberURL, nil)
				getReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
				client := &http.Client{}
				getResp, err := client.Do(getReq)
				assert.NoError(t, err)
				if getResp != nil {
					defer getResp.Body.Close()
					if getResp.StatusCode == 200 {
						var member map[string]interface{}
						body, _ := io.ReadAll(getResp.Body)
						json.Unmarshal(body, &member)
						assert.Equal(t, fmt.Sprintf("new-unique-%s@robot.test.com", testUUID), member["robot_email"])
					}
				}
			},
		},
		{
			"update robot_email to duplicate email",
			func() (string, string) {
				// Create two robots
				memberID1, email1 := createTestRobot("5a")
				_, _ = createTestRobot("5b")
				return memberID1, email1
			},
			map[string]interface{}{
				"robot_email": fmt.Sprintf("test-robot-%s-5b@robot.test.com", testUUID),
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			409,
			"should reject duplicate robot_email",
			nil,
		},
		{
			"update autonomous_mode variations",
			func() (string, string) { return createTestRobot("6") },
			map[string]interface{}{
				"autonomous_mode": "1",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should handle autonomous_mode=1",
			func(t *testing.T, memberID string) {
				getMemberURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
				getReq, _ := http.NewRequest("GET", getMemberURL, nil)
				getReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
				client := &http.Client{}
				getResp, err := client.Do(getReq)
				assert.NoError(t, err)
				if getResp != nil {
					defer getResp.Body.Close()
					if getResp.StatusCode == 200 {
						var member map[string]interface{}
						body, _ := io.ReadAll(getResp.Body)
						json.Unmarshal(body, &member)
						// autonomous_mode should be enabled
						autonomousMode := member["autonomous_mode"]
						assert.True(t, autonomousMode == true || autonomousMode == float64(1) || autonomousMode == int64(1))
					}
				}
			},
		},
		{
			"update robot status",
			func() (string, string) { return createTestRobot("7") },
			map[string]interface{}{
				"status":       "inactive",
				"robot_status": "error",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update robot status fields",
			func(t *testing.T, memberID string) {
				getMemberURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
				getReq, _ := http.NewRequest("GET", getMemberURL, nil)
				getReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
				client := &http.Client{}
				getResp, err := client.Do(getReq)
				assert.NoError(t, err)
				if getResp != nil {
					defer getResp.Body.Close()
					if getResp.StatusCode == 200 {
						var member map[string]interface{}
						body, _ := io.ReadAll(getResp.Body)
						json.Unmarshal(body, &member)
						assert.Equal(t, "inactive", member["status"])
						assert.Equal(t, "error", member["robot_status"])
					}
				}
			},
		},
		{
			"update array fields",
			func() (string, string) { return createTestRobot("8") },
			map[string]interface{}{
				"agents":             []string{"new-agent1", "new-agent2", "new-agent3"},
				"mcp_tools":          []string{"new-tool1"},
				"authorized_senders": []string{"sender1@test.com", "sender2@test.com"},
				"email_filter_rules": []string{".*@allowed\\.com$"},
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update array fields",
			nil,
		},
		{
			"update non-existent robot",
			func() (string, string) { return "non-existent-member-id", "" },
			map[string]interface{}{
				"name": "Should Fail",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent robot",
			nil,
		},
		{
			"update regular user member as robot",
			func() (string, string) {
				// Create a regular user member instead of robot
				memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "regular-user-"+testUUID)
				return memberID, ""
			},
			map[string]interface{}{
				"name": "Should Fail",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should reject updating non-robot member",
			nil,
		},
		{
			"update robot in non-existent team",
			func() (string, string) { return createTestRobot("10") },
			map[string]interface{}{
				"name": "Should Fail",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent team",
			nil,
		},
		{
			"update robot with invalid JSON",
			func() (string, string) { return createTestRobot("11") },
			nil, // Will send invalid JSON
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should handle invalid JSON",
			nil,
		},
		{
			"update robot with empty body",
			func() (string, string) { return createTestRobot("12") },
			map[string]interface{}{},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should handle empty update (no-op)",
			nil,
		},
		{
			"update robot avatar",
			func() (string, string) { return createTestRobot("13") },
			map[string]interface{}{
				"name":        "Robot with Avatar",
				"robot_email": fmt.Sprintf("robot-avatar-%s@robot.test.com", testUUID),
				"avatar":      fmt.Sprintf("https://example.com/avatars/robot-%s.png", testUUID),
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update robot avatar successfully",
			func(t *testing.T, memberID string) {
				// Verify the avatar was updated
				getMemberURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
				getReq, _ := http.NewRequest("GET", getMemberURL, nil)
				getReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
				client := &http.Client{}
				getResp, err := client.Do(getReq)
				assert.NoError(t, err)
				if getResp != nil {
					defer getResp.Body.Close()
					if getResp.StatusCode == 200 {
						var member map[string]interface{}
						body, _ := io.ReadAll(getResp.Body)
						json.Unmarshal(body, &member)
						assert.Equal(t, "Robot with Avatar", member["display_name"])
						assert.Equal(t, fmt.Sprintf("https://example.com/avatars/robot-%s.png", testUUID), member["avatar"], "Should have correct avatar URL")
					}
				}
			},
		},
		{
			"update only robot avatar",
			func() (string, string) { return createTestRobot("14") },
			map[string]interface{}{
				"avatar": fmt.Sprintf("https://example.com/avatars/updated-%s.png", testUUID),
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update only avatar without affecting other fields",
			func(t *testing.T, memberID string) {
				// Verify only avatar was updated
				getMemberURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
				getReq, _ := http.NewRequest("GET", getMemberURL, nil)
				getReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
				client := &http.Client{}
				getResp, err := client.Do(getReq)
				assert.NoError(t, err)
				if getResp != nil {
					defer getResp.Body.Close()
					if getResp.StatusCode == 200 {
						var member map[string]interface{}
						body, _ := io.ReadAll(getResp.Body)
						json.Unmarshal(body, &member)
						// Avatar should be updated
						assert.Equal(t, fmt.Sprintf("https://example.com/avatars/updated-%s.png", testUUID), member["avatar"], "Should have updated avatar URL")
						// Original fields should remain
						assert.Equal(t, "Test Robot 14", member["display_name"], "Name should remain unchanged")
						assert.Equal(t, "gpt-3.5-turbo", member["language_model"], "LLM should remain unchanged")
					}
				}
			},
		},
		{
			"update workspace to unbind",
			func() (string, string) { return createTestRobot("15") },
			map[string]interface{}{
				"workspace": "",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should unbind workspace by setting to empty string",
			func(t *testing.T, memberID string) {
				getMemberURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
				getReq, _ := http.NewRequest("GET", getMemberURL, nil)
				getReq.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
				client := &http.Client{}
				getResp, err := client.Do(getReq)
				assert.NoError(t, err)
				if getResp != nil {
					defer getResp.Body.Close()
					if getResp.StatusCode == 200 {
						var member map[string]interface{}
						body, _ := io.ReadAll(getResp.Body)
						json.Unmarshal(body, &member)
						assert.Empty(t, member["workspace"], "Workspace should be empty after unbinding")
					}
				}
			},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			memberID, _ := tc.setupFunc()

			// Use non-existent team ID for the specific test case
			targetTeamID := teamID
			if tc.name == "update robot in non-existent team" {
				targetTeamID = "non-existent-team-id"
			}

			requestURL := serverURL + baseURL + "/user/teams/" + targetTeamID + "/members/robots/" + memberID

			var req *http.Request
			var err error

			if tc.body == nil {
				// Send invalid JSON for invalid JSON test case
				req, err = http.NewRequest("PUT", requestURL, bytes.NewBufferString("invalid json"))
			} else {
				bodyBytes, _ := json.Marshal(tc.body)
				req, err = http.NewRequest("PUT", requestURL, bytes.NewBuffer(bodyBytes))
			}
			assert.NoError(t, err, "Should create HTTP request")

			req.Header.Set("Content-Type", "application/json")

			// Add headers
			for key, value := range tc.headers {
				req.Header.Set(key, value)
			}

			client := &http.Client{}
			resp, err := client.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				if resp.StatusCode == 200 {
					// Parse response as success message
					var response map[string]interface{}
					err = json.Unmarshal(body, &response)
					assert.NoError(t, err, "Should parse JSON response")

					assert.Contains(t, response, "message", "Should have success message")
					assert.Equal(t, "Robot member updated successfully", response["message"], "Should have correct success message")

					// Run custom validation if provided
					if tc.validateFn != nil {
						tc.validateFn(t, memberID)
					}
				}

				t.Logf("Robot member update test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// TestMemberProfileGet tests the GET /user/teams/:team_id/members/:user_id/profile endpoint
func TestMemberProfileGet(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register a test client for OAuth authentication
	testClient := testutils.RegisterTestClient(t, "Member Profile Get Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, testClient.ClientID)

	// Obtain access token with root permission
	tokenInfo := testutils.ObtainAccessTokenWithRootPermission(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile system:root")

	// Create a test team
	createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Member Profile Get Test Team")
	teamID := getTeamID(createdTeam)

	// The creator is automatically a member, so we can use their user_id
	userID := tokenInfo.UserID

	// Update the member profile first to have test data
	provider := testutils.GetUserProvider(t)
	ctx := context.Background()
	updateData := maps.MapStrAny{
		"display_name": "Test Display Name",
		"bio":          "Test bio description",
		"avatar":       "https://example.com/test-avatar.png",
		"email":        "test-member@example.com",
	}
	err := provider.UpdateMember(ctx, teamID, userID, updateData)
	assert.NoError(t, err, "Should update member profile for testing")

	testCases := []struct {
		name       string
		teamID     string
		userID     string
		headers    map[string]string
		expectCode int
		expectMsg  string
		validateFn func(*testing.T, map[string]interface{}) // Optional validation function
	}{
		{
			"get profile without authentication",
			teamID,
			userID,
			map[string]string{},
			401,
			"should require authentication",
			nil,
		},
		{
			"get own profile successfully",
			teamID,
			userID,
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should return own profile successfully",
			func(t *testing.T, profile map[string]interface{}) {
				// Verify profile structure
				assert.Contains(t, profile, "user_id", "Should have user_id")
				assert.Contains(t, profile, "team_id", "Should have team_id")
				assert.Contains(t, profile, "display_name", "Should have display_name")
				assert.Contains(t, profile, "bio", "Should have bio")
				assert.Contains(t, profile, "avatar", "Should have avatar")
				assert.Contains(t, profile, "email", "Should have email")

				// Verify values
				assert.Equal(t, userID, profile["user_id"], "Should have correct user_id")
				assert.Equal(t, teamID, profile["team_id"], "Should have correct team_id")
				assert.Equal(t, "Test Display Name", profile["display_name"], "Should have correct display_name")
				assert.Equal(t, "Test bio description", profile["bio"], "Should have correct bio")
				assert.Equal(t, "https://example.com/test-avatar.png", profile["avatar"], "Should have correct avatar")
				assert.Equal(t, "test-member@example.com", profile["email"], "Should have correct email")
			},
		},
		{
			"get profile from non-existent team",
			"non-existent-team-id",
			userID,
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent team",
			nil,
		},
		{
			"get profile for non-existent user",
			teamID,
			"non-existent-user-id",
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent user",
			nil,
		},
		{
			"get profile with minimal data",
			teamID,
			userID,
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should return profile even with minimal data",
			func(t *testing.T, profile map[string]interface{}) {
				// Should always have these fields, even if empty
				assert.Contains(t, profile, "user_id", "Should have user_id field")
				assert.Contains(t, profile, "team_id", "Should have team_id field")
				assert.Contains(t, profile, "display_name", "Should have display_name field")
				assert.Contains(t, profile, "bio", "Should have bio field")
				assert.Contains(t, profile, "avatar", "Should have avatar field")
				assert.Contains(t, profile, "email", "Should have email field")
			},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			requestURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members/" + tc.userID + "/profile"

			req, err := http.NewRequest("GET", requestURL, nil)
			assert.NoError(t, err, "Should create HTTP request")

			// Add headers
			for key, value := range tc.headers {
				req.Header.Set(key, value)
			}

			client := &http.Client{}
			resp, err := client.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				if resp.StatusCode == 200 {
					// Parse response as profile object
					var profile map[string]interface{}
					err = json.Unmarshal(body, &profile)
					assert.NoError(t, err, "Should parse JSON response")

					// Run custom validation if provided
					if tc.validateFn != nil {
						tc.validateFn(t, profile)
					}
				}

				t.Logf("Member profile get test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// TestMemberProfileUpdate tests the PUT /user/teams/:team_id/members/:user_id/profile endpoint
func TestMemberProfileUpdate(t *testing.T) {
	// Initialize test environment
	serverURL := testutils.Prepare(t)
	defer testutils.Clean()

	// Get base URL from server config
	baseURL := ""
	if openapi.Server != nil && openapi.Server.Config != nil {
		baseURL = openapi.Server.Config.BaseURL
	}

	// Register a test client for OAuth authentication
	testClient := testutils.RegisterTestClient(t, "Member Profile Update Test Client", []string{"https://localhost/callback"})
	defer testutils.CleanupTestClient(t, testClient.ClientID)

	// Obtain access token with root permission and explicit member profile scope
	tokenInfo := testutils.ObtainAccessTokenWithRootPermission(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile system:root member:profile:update:own")

	// Create a test team
	createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Member Profile Update Test Team")
	teamID := getTeamID(createdTeam)

	// The creator is automatically a member, so we can use their user_id
	userID := tokenInfo.UserID

	testCases := []struct {
		name       string
		teamID     string
		userID     string
		body       map[string]interface{}
		headers    map[string]string
		expectCode int
		expectMsg  string
		validateFn func(*testing.T, string) // Optional validation function with userID
	}{
		{
			"update profile without authentication",
			teamID,
			userID,
			map[string]interface{}{
				"display_name": "New Name",
			},
			map[string]string{},
			401,
			"should require authentication",
			nil,
		},
		{
			"update display_name",
			teamID,
			userID,
			map[string]interface{}{
				"display_name": "Updated Display Name",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update display_name successfully",
			func(t *testing.T, uid string) {
				// Verify the update by getting member details
				provider := testutils.GetUserProvider(t)
				member, err := provider.GetMember(context.Background(), teamID, uid)
				assert.NoError(t, err)
				assert.Equal(t, "Updated Display Name", member["display_name"])
			},
		},
		{
			"update bio",
			teamID,
			userID,
			map[string]interface{}{
				"bio": "This is my updated bio",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update bio successfully",
			func(t *testing.T, uid string) {
				provider := testutils.GetUserProvider(t)
				member, err := provider.GetMember(context.Background(), teamID, uid)
				assert.NoError(t, err)
				assert.Equal(t, "This is my updated bio", member["bio"])
			},
		},
		{
			"update avatar",
			teamID,
			userID,
			map[string]interface{}{
				"avatar": "https://example.com/avatar.png",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update avatar successfully",
			func(t *testing.T, uid string) {
				provider := testutils.GetUserProvider(t)
				member, err := provider.GetMember(context.Background(), teamID, uid)
				assert.NoError(t, err)
				assert.Equal(t, "https://example.com/avatar.png", member["avatar"])
			},
		},
		{
			"update email",
			teamID,
			userID,
			map[string]interface{}{
				"email": "newemail@example.com",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update email successfully",
			func(t *testing.T, uid string) {
				provider := testutils.GetUserProvider(t)
				member, err := provider.GetMember(context.Background(), teamID, uid)
				assert.NoError(t, err)
				assert.Equal(t, "newemail@example.com", member["email"])
			},
		},
		{
			"update all fields at once",
			teamID,
			userID,
			map[string]interface{}{
				"display_name": "Complete Update",
				"bio":          "All fields updated",
				"avatar":       "https://example.com/complete.png",
				"email":        "complete@example.com",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should update all fields successfully",
			func(t *testing.T, uid string) {
				provider := testutils.GetUserProvider(t)
				member, err := provider.GetMember(context.Background(), teamID, uid)
				assert.NoError(t, err)
				assert.Equal(t, "Complete Update", member["display_name"])
				assert.Equal(t, "All fields updated", member["bio"])
				assert.Equal(t, "https://example.com/complete.png", member["avatar"])
				assert.Equal(t, "complete@example.com", member["email"])
			},
		},
		{
			"update with empty body",
			teamID,
			userID,
			map[string]interface{}{},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should reject empty update",
			nil,
		},
		{
			"update other user's profile should fail",
			teamID,
			"other-user-id",
			map[string]interface{}{
				"display_name": "Should Fail",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent user (member not found)",
			nil,
		},
		{
			"update profile in non-existent team",
			"non-existent-team-id",
			userID,
			map[string]interface{}{
				"display_name": "Should Fail",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			404,
			"should return not found for non-existent team",
			nil,
		},
		{
			"update with invalid JSON",
			teamID,
			userID,
			nil, // Will send invalid JSON
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			400,
			"should handle invalid JSON",
			nil,
		},
		{
			"partial update - single field",
			teamID,
			userID,
			map[string]interface{}{
				"display_name": "Partial Update",
			},
			map[string]string{
				"Authorization": "Bearer " + tokenInfo.AccessToken,
			},
			200,
			"should handle partial update with single field",
			func(t *testing.T, uid string) {
				provider := testutils.GetUserProvider(t)
				member, err := provider.GetMember(context.Background(), teamID, uid)
				assert.NoError(t, err)
				assert.Equal(t, "Partial Update", member["display_name"])
				// Other fields should remain unchanged
			},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			requestURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members/" + tc.userID + "/profile"

			var req *http.Request
			var err error

			if tc.body == nil {
				// Send invalid JSON for invalid JSON test case
				req, err = http.NewRequest("PUT", requestURL, bytes.NewBufferString("invalid json"))
			} else {
				bodyBytes, _ := json.Marshal(tc.body)
				req, err = http.NewRequest("PUT", requestURL, bytes.NewBuffer(bodyBytes))
			}
			assert.NoError(t, err, "Should create HTTP request")

			req.Header.Set("Content-Type", "application/json")

			// Add headers
			for key, value := range tc.headers {
				req.Header.Set(key, value)
			}

			client := &http.Client{}
			resp, err := client.Do(req)
			assert.NoError(t, err, "HTTP request should succeed")

			if resp != nil {
				defer resp.Body.Close()
				assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)

				body, err := io.ReadAll(resp.Body)
				assert.NoError(t, err, "Should read response body")

				if resp.StatusCode == 200 {
					// Parse response as success message
					var response map[string]interface{}
					err = json.Unmarshal(body, &response)
					assert.NoError(t, err, "Should parse JSON response")

					assert.Contains(t, response, "user_id", "Should have user_id")
					assert.Contains(t, response, "message", "Should have success message")
					assert.Equal(t, tc.userID, response["user_id"], "Should have correct user_id")
					assert.Equal(t, "Member profile updated successfully", response["message"], "Should have correct success message")

					// Run custom validation if provided
					if tc.validateFn != nil {
						tc.validateFn(t, tc.userID)
					}
				}

				t.Logf("Member profile update test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
			}
		})
	}
}

// Note: getTeamID function is already defined in team_test.go
