package sfcrmappservice

import (
	"context"
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"sort"
	"strings"
	"sync/atomic"
	"testing"
	"time"

	"github.com/pingcap-inc/nexuscrm-api-host/runtimegrpc"
	authorizationsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/authorizationv1"
	querysemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1"
	mutationsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordmutationv1"
	sessionsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/sessionv1"
)

func TestSCIMRouteIsNotPublishedByAppService(t *testing.T) {
	service := newTestService(t, &fakeRuntime{})
	request := httptest.NewRequest(http.MethodGet, "/scim/v2/ServiceProviderConfig", nil)
	recorder := httptest.NewRecorder()

	service.ServeHTTP(recorder, request)

	if recorder.Code != http.StatusNotFound {
		t.Fatalf("status=%d body=%s; want unpublished SCIM route to return 404", recorder.Code, recorder.Body.String())
	}
}

func TestDormantSCIMDiscoveryRejectsMissingCredential(t *testing.T) {
	service := newTestService(t, &fakeRuntime{})
	request := httptest.NewRequest(http.MethodGet, "/scim/v2/ServiceProviderConfig", nil)
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusUnauthorized {
		t.Fatalf("status=%d body=%s; want dormant SCIM handler to reject missing credentials", recorder.Code, recorder.Body.String())
	}
	if got := recorder.Header().Get("Content-Type"); !strings.HasPrefix(got, "application/scim+json") {
		t.Fatalf("Content-Type=%q; want application/scim+json", got)
	}
	if body := recorder.Body.String(); !strings.Contains(body, `"urn:ietf:params:scim:api:messages:2.0:Error"`) {
		t.Fatalf("body=%s; want RFC 7644 error envelope", body)
	}
}

func TestSCIMCreateAssignsZeroAccessProfileAndNoRole(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	created := false
	query := func(_ context.Context, bearer string, request querysemantic.Request) (querysemantic.Response, error) {
		if bearer != "access-token" {
			t.Fatalf("query bearer=%q", bearer)
		}
		switch request.ObjectID {
		case "IdentitySyncSetting":
			response := scimQueryResponse(scimQueryRecord("IdentitySyncSetting", map[string]any{
				"Name": "default", "DefaultProfileName": "SCIM Zero Access",
				"ServiceUsername":    "scim-provisioning@scim.nexuscrm.invalid",
				"ServiceProfileName": "Minimum Access - API Only Integrations",
				"ExemptPrincipals":   "admin@example.invalid",
				"TimeZoneSidKey":     "UTC", "LocaleSidKey": "en_US",
				"EmailEncodingKey": "UTF-8", "LanguageLocaleKey": "en_US",
				"BreakerFailureThreshold": int64(2), "BreakerCooldownSeconds": int64(300),
				"TokenTtlHours": int64(8760),
			}))
			if err := querysemantic.ValidateResponse(response); err != nil {
				t.Fatalf("invalid policy response: %v %#v", err, response)
			}
			return response, nil
		case "Profile":
			name := scimPredicateString(request.Filter)
			id := "zero-profile-id"
			if name == "Minimum Access - API Only Integrations" {
				id = "service-profile-id"
			}
			return scimQueryResponse(scimQueryRecord("Profile", map[string]any{"Id": id, "Name": name})), nil
		case "User":
			if !created {
				return scimQueryResponse(), nil
			}
			return scimQueryResponse(scimQueryRecord("User", map[string]any{
				"Id": "new-user-id", "Username": "new.user@example.com", "Email": "new.user@example.com",
				"FirstName": "New", "LastName": "User", "Title": "Engineer", "Department": "/Engineering",
				"IsActive": true,
			})), nil
		default:
			t.Fatalf("unexpected query object=%s", request.ObjectID)
			return querysemantic.Response{}, nil
		}
	}
	var gotMutation mutationsemantic.Request
	mutate := func(_ context.Context, bearer string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		if bearer != "access-token" {
			t.Fatalf("mutation bearer=%q", bearer)
		}
		gotMutation = request
		created = true
		return successfulMutationResponse(t, request), nil
	}
	service := newSCIMTestService(t, &config, query, mutate)
	body := `{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User","urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],"userName":"new.user@example.com","name":{"givenName":"New","familyName":"User"},"displayName":"New User","title":"Engineer","emails":[{"value":"new.user@example.com","primary":true}],"active":true,"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User":{"department":"/Engineering","manager":{"value":"manager@example.com"}}}`
	request := httptest.NewRequest(http.MethodPost, "/scim/v2/Users", strings.NewReader(body))
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	request.Header.Set("Content-Type", "application/scim+json")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusCreated {
		t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
	}
	if len(gotMutation.Operations) != 1 || gotMutation.Operations[0].Kind != mutationsemantic.OperationCreate || gotMutation.Operations[0].ObjectID != "User" {
		t.Fatalf("mutation=%#v", gotMutation)
	}
	fields := scimMutationFields(gotMutation.Operations[0].Fields)
	if fields["ProfileId"] != "zero-profile-id" || fields["UserRoleId"] != nil || fields["Username"] != "new.user@example.com" || fields["Department"] != "/Engineering" {
		t.Fatalf("create fields=%#v", fields)
	}
	for _, absent := range []string{"Company", "CompanyName", "Division", "ManagerId"} {
		if _, exists := fields[absent]; exists {
			t.Fatalf("unexpected field %s in %#v", absent, fields)
		}
	}
}

func TestSCIMCreateRejectsUsernameAndEmailResolvingToDifferentUsers(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		if request.ObjectID != "User" {
			t.Fatalf("unexpected query object=%s", request.ObjectID)
		}
		id := "user-by-username"
		if request.Filter.Left.Field == "Email" {
			id = "user-by-email"
		}
		return scimQueryResponse(scimQueryRecord("User", map[string]any{
			"Id": id, "Username": "existing@example.com", "Email": "existing@example.com",
			"FirstName": "Existing", "LastName": "User", "IsActive": true,
		})), nil
	}
	var mutations atomic.Uint64
	service := newSCIMTestService(t, &config, query, func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		mutations.Add(1)
		return successfulMutationResponse(t, request), nil
	})
	body := `{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"userName":"username@example.com","name":{"familyName":"User"},"emails":[{"value":"email@example.com","primary":true}],"active":true}`
	request := httptest.NewRequest(http.MethodPost, "/scim/v2/Users", strings.NewReader(body))
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusConflict || mutations.Load() != 0 || !strings.Contains(recorder.Body.String(), `"scimType":"uniqueness"`) {
		t.Fatalf("status=%d mutations=%d body=%s", recorder.Code, mutations.Load(), recorder.Body.String())
	}
}

func TestSCIMDeleteDeactivatesWithoutDeletingOrChangingPermissions(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		if request.ObjectID == "User" {
			return scimQueryResponse(scimQueryRecord("User", map[string]any{
				"Id": "employee-id", "Username": "employee@example.com", "Email": "employee@example.com",
				"FirstName": "Test", "LastName": "Employee", "IsActive": true,
			})), nil
		}
		t.Fatalf("unexpected query object=%s", request.ObjectID)
		return querysemantic.Response{}, nil
	}
	var got []mutationsemantic.Request
	mutate := func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		got = append(got, request)
		return successfulMutationResponse(t, request), nil
	}
	service := newSCIMTestService(t, &config, query, mutate)
	request := httptest.NewRequest(http.MethodDelete, "/scim/v2/Users/employee-id", nil)
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusNoContent {
		t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
	}
	if len(got) != 2 {
		t.Fatalf("mutations=%#v; DELETE must reserve one durable slot before the User update", got)
	}
	if len(got[0].Operations) != 1 || got[0].Operations[0].Kind != mutationsemantic.OperationCreate || got[0].Operations[0].ObjectID != "IdentitySyncDeactivationTicket" {
		t.Fatalf("ticket mutation=%#v", got[0])
	}
	ticketFields := scimMutationFields(got[0].Operations[0].Fields)
	if ticketFields["Name"] == "" || ticketFields["Bucket"] == nil || ticketFields["Slot"] == nil {
		t.Fatalf("ticket fields=%#v", ticketFields)
	}
	if len(got[1].Operations) != 1 || got[1].Operations[0].Kind != mutationsemantic.OperationUpdate || got[1].Operations[0].ObjectID != "User" || got[1].Operations[0].RecordID != "employee-id" {
		t.Fatalf("User mutation=%#v; DELETE must lower to one User update", got[1])
	}
	fields := scimMutationFields(got[1].Operations[0].Fields)
	if len(fields) != 1 || fields["IsActive"] != false {
		t.Fatalf("deactivation fields=%#v; want only IsActive=false", fields)
	}
}

func TestSCIMDeleteStopsWhenFleetWideDeactivationSlotsAreFull(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		if request.ObjectID == "User" {
			return scimQueryResponse(scimQueryRecord("User", map[string]any{
				"Id": "employee-id", "Username": "employee@example.com", "Email": "employee@example.com",
				"FirstName": "Test", "LastName": "Employee", "IsActive": true,
			})), nil
		}
		t.Fatalf("unexpected query object=%s", request.ObjectID)
		return querysemantic.Response{}, nil
	}
	var ticketAttempts atomic.Uint64
	var userMutations atomic.Uint64
	mutate := func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		if len(request.Operations) != 1 {
			t.Fatalf("mutation=%#v", request)
		}
		if request.Operations[0].ObjectID == "User" {
			userMutations.Add(1)
			return successfulMutationResponse(t, request), nil
		}
		if request.Operations[0].ObjectID != "IdentitySyncDeactivationTicket" {
			t.Fatalf("mutation=%#v", request)
		}
		ticketAttempts.Add(1)
		return failedSCIMMutationResponse(t, request, mutationsemantic.ErrorFieldIntegrity), nil
	}
	service := newSCIMTestService(t, &config, query, mutate)
	request := httptest.NewRequest(http.MethodDelete, "/scim/v2/Users/employee-id", nil)
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusTooManyRequests || ticketAttempts.Load() != 2 || userMutations.Load() != 0 {
		t.Fatalf("status=%d ticketAttempts=%d userMutations=%d body=%s", recorder.Code, ticketAttempts.Load(), userMutations.Load(), recorder.Body.String())
	}
}

func TestSCIMPatchActiveFalseReservesSlotBeforeDeactivation(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	active := true
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		if request.ObjectID == "User" {
			return scimQueryResponse(scimQueryRecord("User", map[string]any{
				"Id": "employee-id", "Username": "employee@example.com", "Email": "employee@example.com",
				"FirstName": "Test", "LastName": "Employee", "IsActive": active,
			})), nil
		}
		t.Fatalf("unexpected query object=%s", request.ObjectID)
		return querysemantic.Response{}, nil
	}
	var objects []string
	mutate := func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		objects = append(objects, request.Operations[0].ObjectID)
		if request.Operations[0].ObjectID == "User" {
			active = false
		}
		return successfulMutationResponse(t, request), nil
	}
	service := newSCIMTestService(t, &config, query, mutate)
	body := `{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"replace","path":"active","value":false}]}`
	request := httptest.NewRequest(http.MethodPatch, "/scim/v2/Users/employee-id", strings.NewReader(body))
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusOK || len(objects) != 2 || objects[0] != "IdentitySyncDeactivationTicket" || objects[1] != "User" {
		t.Fatalf("status=%d mutationObjects=%#v body=%s", recorder.Code, objects, recorder.Body.String())
	}
}

func TestSCIMDeleteOfInactiveUserDoesNotConsumeDeactivationSlot(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		if request.ObjectID == "User" {
			return scimQueryResponse(scimQueryRecord("User", map[string]any{
				"Id": "employee-id", "Username": "employee@example.com", "Email": "employee@example.com",
				"FirstName": "Test", "LastName": "Employee", "IsActive": false,
			})), nil
		}
		t.Fatalf("unexpected query object=%s", request.ObjectID)
		return querysemantic.Response{}, nil
	}
	var mutations atomic.Uint64
	service := newSCIMTestService(t, &config, query, func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		mutations.Add(1)
		return successfulMutationResponse(t, request), nil
	})
	request := httptest.NewRequest(http.MethodDelete, "/scim/v2/Users/employee-id", nil)
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusNoContent || mutations.Load() != 0 {
		t.Fatalf("status=%d mutations=%d body=%s", recorder.Code, mutations.Load(), recorder.Body.String())
	}
}

func TestSCIMRehireReactivatesAndPreservesExistingProfileAndRole(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	active := false
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		if request.ObjectID == "User" {
			return scimQueryResponse(scimQueryRecord("User", map[string]any{
				"Id": "rehire-id", "Username": "rehire@example.com", "Email": "rehire@example.com",
				"FirstName": "Re", "LastName": "Hire", "IsActive": active,
			})), nil
		}
		t.Fatalf("unexpected query object=%s", request.ObjectID)
		return querysemantic.Response{}, nil
	}
	var got mutationsemantic.Request
	mutate := func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		got = request
		active = true
		return successfulMutationResponse(t, request), nil
	}
	service := newSCIMTestService(t, &config, query, mutate)
	body := `{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"replace","path":"active","value":true}]}`
	request := httptest.NewRequest(http.MethodPatch, "/scim/v2/Users/rehire-id", strings.NewReader(body))
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusOK {
		t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
	}
	fields := scimMutationFields(got.Operations[0].Fields)
	if len(fields) != 1 || fields["IsActive"] != true {
		t.Fatalf("rehire fields=%#v; profile and role must be preserved", fields)
	}
	if _, exists := fields["ProfileId"]; exists {
		t.Fatalf("rehire must not replace ProfileId: %#v", fields)
	}
	if _, exists := fields["UserRoleId"]; exists {
		t.Fatalf("rehire must not replace UserRoleId: %#v", fields)
	}
}

func TestSCIMPutDoesNotOwnOrClearManager(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		if request.ObjectID == "User" {
			return scimQueryResponse(scimQueryRecord("User", map[string]any{
				"Id": "employee-id", "Username": "employee@example.com", "Email": "employee@example.com",
				"FirstName": "Test", "LastName": "Employee", "Title": "Old", "IsActive": true,
			})), nil
		}
		t.Fatalf("unexpected query object=%s", request.ObjectID)
		return querysemantic.Response{}, nil
	}
	var got mutationsemantic.Request
	mutate := func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		got = request
		return successfulMutationResponse(t, request), nil
	}
	service := newSCIMTestService(t, &config, query, mutate)
	body := `{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User","urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],"userName":"employee@example.com","name":{"givenName":"Test","familyName":"Employee"},"emails":[{"value":"employee@example.com","primary":true}],"title":"New","active":true,"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User":{"manager":{"value":"manager@example.com"}}}`
	request := httptest.NewRequest(http.MethodPut, "/scim/v2/Users/employee-id", strings.NewReader(body))
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusOK {
		t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
	}
	fields := scimMutationFields(got.Operations[0].Fields)
	if _, exists := fields["ManagerId"]; exists {
		t.Fatalf("Helix PUT must not clear or write ManagerId: %#v", fields)
	}
	if _, exists := fields["ProfileId"]; exists {
		t.Fatalf("Helix PUT must preserve ProfileId: %#v", fields)
	}
	if _, exists := fields["UserRoleId"]; exists {
		t.Fatalf("Helix PUT must preserve UserRoleId: %#v", fields)
	}
}

func TestSCIMPutRejectsIdentityResolvingToDifferentUsersBeforeMutation(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		if request.ObjectID != "User" {
			t.Fatalf("unexpected query object=%s", request.ObjectID)
		}
		id := "target-id"
		if request.Filter.Left.Field == "Email" {
			id = "different-user-id"
		}
		return scimQueryResponse(scimQueryRecord("User", map[string]any{
			"Id": id, "Username": "target@example.com", "Email": "target@example.com",
			"FirstName": "Target", "LastName": "User", "IsActive": true,
		})), nil
	}
	var mutations atomic.Uint64
	service := newSCIMTestService(t, &config, query, func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		mutations.Add(1)
		return successfulMutationResponse(t, request), nil
	})
	body := `{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"userName":"target@example.com","name":{"familyName":"User"},"emails":[{"value":"different@example.com","primary":true}],"active":true}`
	request := httptest.NewRequest(http.MethodPut, "/scim/v2/Users/target-id", strings.NewReader(body))
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusConflict || mutations.Load() != 0 || !strings.Contains(recorder.Body.String(), `"scimType":"uniqueness"`) {
		t.Fatalf("status=%d mutations=%d body=%s", recorder.Code, mutations.Load(), recorder.Body.String())
	}
}

func TestSCIMUserMutationRejectsWrongRunAsPrincipal(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	config.RuntimeReadSession = func(context.Context, runtimegrpc.SessionPresentedCredentials, sessionsemantic.ReadRequest) (sessionsemantic.ReadResponse, runtimegrpc.SessionIssuedCredentials, error) {
		return sessionsemantic.ReadResponse{Session: sessionsemantic.Session{Principal: sessionsemantic.Principal{
			PrincipalID: "wrong-user", DisplayName: "Wrong User", Email: "wrong@example.com", ProfileID: "service-profile-id",
		}, ExpiresAtUnixSecond: time.Now().Add(time.Minute).Unix()}}, runtimegrpc.SessionIssuedCredentials{}, nil
	}
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		t.Fatalf("wrong principal must be rejected before User query: %s", request.ObjectID)
		return querysemantic.Response{}, nil
	}
	var mutations atomic.Uint64
	service := newSCIMTestService(t, &config, query, func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		mutations.Add(1)
		return successfulMutationResponse(t, request), nil
	})
	request := httptest.NewRequest(http.MethodDelete, "/scim/v2/Users/employee-id", nil)
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusForbidden || mutations.Load() != 0 {
		t.Fatalf("status=%d mutations=%d body=%s", recorder.Code, mutations.Load(), recorder.Body.String())
	}
}

func TestSCIMDeleteProtectsExemptPrincipal(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		if request.ObjectID == "User" {
			return scimQueryResponse(scimQueryRecord("User", map[string]any{
				"Id": "admin-id", "Username": "admin@example.invalid", "Email": "admin@example.invalid",
				"FirstName": "Break", "LastName": "Glass", "IsActive": true,
			})), nil
		}
		t.Fatalf("unexpected query object=%s", request.ObjectID)
		return querysemantic.Response{}, nil
	}
	var mutations atomic.Uint64
	service := newSCIMTestService(t, &config, query, func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		mutations.Add(1)
		return successfulMutationResponse(t, request), nil
	})
	request := httptest.NewRequest(http.MethodDelete, "/scim/v2/Users/admin-id", nil)
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusForbidden || mutations.Load() != 0 || !strings.Contains(recorder.Body.String(), `"scimType":"mutability"`) {
		t.Fatalf("status=%d mutations=%d body=%s", recorder.Code, mutations.Load(), recorder.Body.String())
	}
}

func scimAuthorizedSessionConfig() SessionHTTPConfig {
	config := sessionTestConfig()
	config.RuntimeReadSession = func(context.Context, runtimegrpc.SessionPresentedCredentials, sessionsemantic.ReadRequest) (sessionsemantic.ReadResponse, runtimegrpc.SessionIssuedCredentials, error) {
		return sessionsemantic.ReadResponse{Session: sessionsemantic.Session{Principal: sessionsemantic.Principal{
			PrincipalID: "service-user-id", DisplayName: "SCIM Provisioning", Email: "scim-provisioning@scim.nexuscrm.invalid", ProfileID: "service-profile-id",
		}, ExpiresAtUnixSecond: time.Now().Add(time.Minute).Unix()}}, runtimegrpc.SessionIssuedCredentials{}, nil
	}
	return config
}

func scimPolicyTestQuery(request querysemantic.Request) (querysemantic.Response, bool) {
	switch request.ObjectID {
	case "IdentitySyncSetting":
		return scimQueryResponse(scimQueryRecord("IdentitySyncSetting", map[string]any{
			"Name": "default", "DefaultProfileName": "SCIM Zero Access",
			"ServiceUsername":    "scim-provisioning@scim.nexuscrm.invalid",
			"ServiceProfileName": "Minimum Access - API Only Integrations",
			"ExemptPrincipals":   "admin@example.invalid",
			"TimeZoneSidKey":     "UTC", "LocaleSidKey": "en_US",
			"EmailEncodingKey": "UTF-8", "LanguageLocaleKey": "en_US",
			"BreakerFailureThreshold": int64(2), "BreakerCooldownSeconds": int64(300),
			"TokenTtlHours": int64(8760),
		})), true
	case "Profile":
		name := scimPredicateString(request.Filter)
		id := "zero-profile-id"
		if name == "Minimum Access - API Only Integrations" {
			id = "service-profile-id"
		}
		return scimQueryResponse(scimQueryRecord("Profile", map[string]any{"Id": id, "Name": name})), true
	default:
		return querysemantic.Response{}, false
	}
}

func newSCIMTestService(t *testing.T, session *SessionHTTPConfig, query RuntimeQueryFunc, mutate RuntimeMutateFunc) *Service {
	t.Helper()
	runtime := &fakeRuntime{}
	runtime.ready.Store(true)
	service, err := NewService(ServiceConfig{
		Session: session, RuntimeEvaluate: runtime.Evaluate, RuntimeReady: runtime.Ready, RuntimeMetrics: runtime.Metrics,
		RuntimeQuery: query,
		RuntimeHistoryQuery: func(context.Context, string, querysemantic.HistoryRequest) (querysemantic.HistoryResponse, error) {
			return querysemantic.HistoryResponse{}, nil
		},
		RuntimeMutate: mutate, RequestTimeout: time.Second, MaxRequestBytes: 64 * 1024,
	})
	if err != nil {
		t.Fatal(err)
	}
	return service
}

func serveDormantSCIMForTest(t *testing.T, service *Service, writer http.ResponseWriter, request *http.Request) {
	t.Helper()
	if !service.serveSCIM(writer, request) {
		t.Fatalf("dormant SCIM handler did not own test path %q", request.URL.Path)
	}
}

func scimQueryResponse(records ...querysemantic.Record) querysemantic.Response {
	return querysemantic.Response{
		TotalSize: uint64(len(records)), Done: true, Records: records,
		Receipts: querysemantic.Receipts{ProtocolVersion: "1.0", CapabilityVersion: querysemantic.CapabilityName, CatalogRevision: 7, SchemaGeneration: 8, EngineGeneration: 9, SecurityEpoch: 10},
	}
}

func scimQueryRecord(object string, fields map[string]any) querysemantic.Record {
	record := querysemantic.Record{ObjectID: object}
	names := make([]string, 0, len(fields))
	for name := range fields {
		names = append(names, name)
	}
	sort.Strings(names)
	for _, name := range names {
		raw := fields[name]
		value := querysemantic.Value{}
		switch typed := raw.(type) {
		case string:
			value.Kind, value.String = querysemantic.ValueString, &typed
		case bool:
			value.Kind, value.Boolean = querysemantic.ValueBoolean, &typed
		case int64:
			value.Kind, value.Integer = querysemantic.ValueInteger, &typed
		case nil:
			value.Kind, value.Null = querysemantic.ValueString, true
		default:
			panic("unsupported SCIM test field")
		}
		record.Fields = append(record.Fields, querysemantic.Field{Name: name, Value: value})
	}
	return record
}

func failedSCIMMutationResponse(t *testing.T, request mutationsemantic.Request, kind mutationsemantic.ErrorKind) mutationsemantic.Response {
	t.Helper()
	digest, err := mutationsemantic.CommandDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	return mutationsemantic.Response{
		CommandID: request.CommandID, CommandDigest: digest,
		Results: []mutationsemantic.OperationResult{{
			Index: 0, Kind: request.Operations[0].Kind, Success: false,
			Errors: []mutationsemantic.OperationError{{Kind: kind, Fields: []string{"Name"}}},
		}},
		Receipts: mutationReceipts(), OutcomeExpiresAtUTC: "2026-08-25T12:30:00Z",
	}
}

func scimPredicateString(predicate querysemantic.Predicate) string {
	if predicate.Right.Literal == nil || predicate.Right.Literal.String == nil {
		return ""
	}
	return *predicate.Right.Literal.String
}

func scimMutationFields(fields []mutationsemantic.FieldValue) map[string]any {
	result := make(map[string]any, len(fields))
	for _, field := range fields {
		switch {
		case field.Null:
			result[field.Name] = nil
		case field.String != nil:
			result[field.Name] = *field.String
		case field.Boolean != nil:
			result[field.Name] = *field.Boolean
		default:
			encoded, _ := json.Marshal(field)
			result[field.Name] = string(encoded)
		}
	}
	return result
}

func TestSCIMDiscoveryExchangesConnectedAppCredentialAndRevokesAccessToken(t *testing.T) {
	config := sessionTestConfig()
	var exchanged, revoked atomic.Uint64
	config.RuntimeExchangeAuthorization = func(_ context.Context, credentials runtimegrpc.AuthorizationExchangeCredentials, request authorizationsemantic.ExchangeRequest) (authorizationsemantic.ExchangeResponse, runtimegrpc.IssuedAuthorizationCredentials, error) {
		exchanged.Add(1)
		if credentials.ClientSecret != "client-secret" || request.ClientID != "client-id" || request.GrantType != authorizationsemantic.GrantTypeClientCredentials {
			t.Fatalf("credentials=%#v request=%#v", credentials, request)
		}
		return authorizationsemantic.ExchangeResponse{Token: &authorizationsemantic.Token{
			TokenType: "Bearer", ExpiresInSecond: 300, AccessTokenIssued: true,
		}}, runtimegrpc.IssuedAuthorizationCredentials{AccessToken: "short-lived-access"}, nil
	}
	config.RuntimeRevokeSession = func(_ context.Context, credentials runtimegrpc.SessionPresentedCredentials, _ sessionsemantic.RevokeRequest) error {
		revoked.Add(1)
		if credentials.AccessToken != "short-lived-access" {
			t.Fatalf("revoked access token=%q", credentials.AccessToken)
		}
		return nil
	}
	runtime := &fakeRuntime{}
	runtime.ready.Store(true)
	service, err := NewService(ServiceConfig{
		Session: &config, RuntimeEvaluate: runtime.Evaluate, RuntimeReady: runtime.Ready,
		RuntimeMetrics: runtime.Metrics,
		RuntimeQuery: func(context.Context, string, querysemantic.Request) (querysemantic.Response, error) {
			return querysemantic.Response{}, nil
		},
		RuntimeHistoryQuery: func(context.Context, string, querysemantic.HistoryRequest) (querysemantic.HistoryResponse, error) {
			return querysemantic.HistoryResponse{}, nil
		},
		RequestTimeout: time.Second, MaxRequestBytes: 64 * 1024,
	})
	if err != nil {
		t.Fatal(err)
	}
	request := httptest.NewRequest(http.MethodGet, "/scim/v2/ServiceProviderConfig", nil)
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusOK || exchanged.Load() != 1 || revoked.Load() != 1 {
		t.Fatalf("status=%d exchanged=%d revoked=%d body=%s", recorder.Code, exchanged.Load(), revoked.Load(), recorder.Body.String())
	}
	if body := recorder.Body.String(); !strings.Contains(body, `"patch":{"supported":true}`) || !strings.Contains(body, `"maxResults":500`) {
		t.Fatalf("ServiceProviderConfig=%s", body)
	}
}

func TestSCIMDiscoveryRejectsRuntimeAccessTokenOutsideBoundAndRevokesIt(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	config.RuntimeExchangeAuthorization = func(context.Context, runtimegrpc.AuthorizationExchangeCredentials, authorizationsemantic.ExchangeRequest) (authorizationsemantic.ExchangeResponse, runtimegrpc.IssuedAuthorizationCredentials, error) {
		return authorizationsemantic.ExchangeResponse{Token: &authorizationsemantic.Token{
			TokenType: "Bearer", ExpiresInSecond: int64(scimRuntimeAccessTokenMaxTTL/time.Second) + 1, AccessTokenIssued: true,
		}}, runtimegrpc.IssuedAuthorizationCredentials{AccessToken: "oversized-access-token"}, nil
	}
	var revoked atomic.Uint64
	config.RuntimeRevokeSession = func(_ context.Context, credentials runtimegrpc.SessionPresentedCredentials, _ sessionsemantic.RevokeRequest) error {
		revoked.Add(1)
		if credentials.AccessToken != "oversized-access-token" {
			t.Fatalf("revoked access token=%q", credentials.AccessToken)
		}
		return nil
	}
	service := newSCIMTestService(t, &config, func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		t.Fatalf("oversized token must be rejected before policy query: %s", request.ObjectID)
		return querysemantic.Response{}, nil
	}, func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		t.Fatalf("oversized token must be rejected before mutation: %#v", request)
		return mutationsemantic.Response{}, nil
	})
	request := httptest.NewRequest(http.MethodGet, "/scim/v2/ServiceProviderConfig", nil)
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusUnauthorized || revoked.Load() != 1 {
		t.Fatalf("status=%d revoked=%d body=%s", recorder.Code, revoked.Load(), recorder.Body.String())
	}
}

func TestSCIMUsersRejectsSessionBeyondTenantTokenTTL(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	config.RuntimeReadSession = func(context.Context, runtimegrpc.SessionPresentedCredentials, sessionsemantic.ReadRequest) (sessionsemantic.ReadResponse, runtimegrpc.SessionIssuedCredentials, error) {
		return sessionsemantic.ReadResponse{Session: sessionsemantic.Session{Principal: sessionsemantic.Principal{
			PrincipalID: "service-user-id", DisplayName: "SCIM Provisioning", Email: "scim-provisioning@scim.nexuscrm.invalid", ProfileID: "service-profile-id",
		}, ExpiresAtUnixSecond: time.Now().Add(2 * time.Hour).Unix()}}, runtimegrpc.SessionIssuedCredentials{}, nil
	}
	query := func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if request.ObjectID == "IdentitySyncSetting" {
			return scimQueryResponse(scimQueryRecord("IdentitySyncSetting", map[string]any{
				"Name": "default", "DefaultProfileName": "SCIM Zero Access",
				"ServiceUsername": "scim-provisioning@scim.nexuscrm.invalid", "ServiceProfileName": "Minimum Access - API Only Integrations",
				"ExemptPrincipals": "admin@example.invalid", "BreakerFailureThreshold": int64(2), "BreakerCooldownSeconds": int64(300),
				"TokenTtlHours": int64(1), "TimeZoneSidKey": "UTC", "LocaleSidKey": "en_US", "EmailEncodingKey": "UTF-8", "LanguageLocaleKey": "en_US",
			})), nil
		}
		if request.ObjectID == "Profile" {
			name := scimPredicateString(request.Filter)
			id := "zero-profile-id"
			if name == "Minimum Access - API Only Integrations" {
				id = "service-profile-id"
			}
			return scimQueryResponse(scimQueryRecord("Profile", map[string]any{"Id": id, "Name": name})), nil
		}
		t.Fatalf("unexpected query object=%s", request.ObjectID)
		return querysemantic.Response{}, nil
	}
	service := newSCIMTestService(t, &config, query, func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		t.Fatalf("overlong session must be rejected before mutation: %#v", request)
		return mutationsemantic.Response{}, nil
	})
	request := httptest.NewRequest(http.MethodGet, "/scim/v2/Users?count=1&startIndex=1", nil)
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusServiceUnavailable {
		t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
	}
}

func TestSCIMDiscoveryRetriesTransientAccessTokenRevocation(t *testing.T) {
	config := scimAuthorizedSessionConfig()
	var revokeCalls atomic.Uint64
	config.RuntimeRevokeSession = func(context.Context, runtimegrpc.SessionPresentedCredentials, sessionsemantic.RevokeRequest) error {
		if revokeCalls.Add(1) < 3 {
			return errors.New("temporary revoke failure")
		}
		return nil
	}
	service := newSCIMTestService(t, &config, func(_ context.Context, _ string, request querysemantic.Request) (querysemantic.Response, error) {
		if response, ok := scimPolicyTestQuery(request); ok {
			return response, nil
		}
		t.Fatalf("unexpected query object=%s", request.ObjectID)
		return querysemantic.Response{}, nil
	}, func(_ context.Context, _ string, request mutationsemantic.Request) (mutationsemantic.Response, error) {
		t.Fatalf("discovery must not mutate: %#v", request)
		return mutationsemantic.Response{}, nil
	})
	request := httptest.NewRequest(http.MethodGet, "/scim/v2/ServiceProviderConfig", nil)
	request.Header.Set("Authorization", "Bearer client-id.client-secret")
	recorder := httptest.NewRecorder()

	serveDormantSCIMForTest(t, service, recorder, request)

	if recorder.Code != http.StatusOK || revokeCalls.Load() != 3 {
		t.Fatalf("status=%d revokeCalls=%d body=%s", recorder.Code, revokeCalls.Load(), recorder.Body.String())
	}
}
