package constants

import (
	"context"
	"testing"
)

func TestStandardActionInternalAccessScope_MatchesOnlyStampedActionObjectOperation(t *testing.T) {
	ctx := WithStandardActionInternalAccessScopes(context.Background(), "sa_convertlead", []StandardActionInternalAccessScope{
		{StandardActionID: "sa_convertlead", ObjectAPIName: "Task", Operation: PermEdit},
		{StandardActionID: "sa_convertlead", ObjectAPIName: "Task", Operation: PermRead},
	})

	if !IsScopedInternalAccess(ctx, "Task", PermEdit) {
		t.Fatal("expected matching standard-action internal access scope")
	}
	if !IsScopedInternalAccess(ctx, "Task", PermRead) {
		t.Fatal("expected read operation to be supported by standard-action internal access scope")
	}
	if ScopedInternalAccessEnforcesFLS(ctx, "Task", PermRead) {
		t.Fatal("default scoped internal read must keep legacy FLS bypass")
	}
	if !ScopedInternalAccessBypassesFLS(ctx, "Task", PermRead) {
		t.Fatal("default scoped internal read must bypass FLS")
	}
	if IsScopedInternalAccess(ctx, "Task", PermCreate) {
		t.Fatal("operation mismatch must not inherit scoped access permission")
	}
	if ScopedInternalAccessEnforcesFLS(ctx, "Task", PermCreate) {
		t.Fatal("operation mismatch must not inherit FLS-preserving policy")
	}
	if ScopedInternalAccessBypassesFLS(ctx, "Task", PermCreate) {
		t.Fatal("operation mismatch must not inherit FLS bypass policy")
	}
	if IsScopedInternalAccess(ctx, "CampaignMember", PermEdit) {
		t.Fatal("object mismatch must not inherit scoped access permission")
	}

	otherActionCtx := WithStandardActionInternalAccessScopes(context.Background(), "sa_other", []StandardActionInternalAccessScope{
		{StandardActionID: "sa_convertlead", ObjectAPIName: "Task", Operation: PermEdit},
	})
	if IsScopedInternalAccess(otherActionCtx, "Task", PermEdit) {
		t.Fatal("scope rows for another standard action must not apply")
	}
}

func TestStandardActionInternalAccessScope_EnforceFLSPreservesScopedAccess(t *testing.T) {
	ctx := WithStandardActionInternalAccessScopes(context.Background(), "sa_read", []StandardActionInternalAccessScope{
		{StandardActionID: "sa_read", ObjectAPIName: "Task", Operation: PermRead, EnforceFLS: true},
	})

	if !IsScopedInternalAccess(ctx, "Task", PermRead) {
		t.Fatal("expected FLS-preserving scope to still grant scoped internal access")
	}
	if !ScopedInternalAccessEnforcesFLS(ctx, "Task", PermRead) {
		t.Fatal("expected matching read scope to enforce FLS")
	}
	if ScopedInternalAccessBypassesFLS(ctx, "Task", PermRead) {
		t.Fatal("FLS-preserving scope must not bypass FLS")
	}
	if ScopedInternalAccessEnforcesFLS(ctx, "Task", PermEdit) {
		t.Fatal("operation mismatch must not inherit FLS-preserving policy")
	}
	if ScopedInternalAccessEnforcesFLS(ctx, "CampaignMember", PermRead) {
		t.Fatal("object mismatch must not inherit FLS-preserving policy")
	}

	otherActionCtx := WithStandardActionInternalAccessScopes(context.Background(), "sa_other", []StandardActionInternalAccessScope{
		{StandardActionID: "sa_read", ObjectAPIName: "Task", Operation: PermRead, EnforceFLS: true},
	})
	if ScopedInternalAccessEnforcesFLS(otherActionCtx, "Task", PermRead) {
		t.Fatal("scope rows for another action must not apply FLS-preserving policy")
	}
}

func TestStandardActionInternalAccessScope_DuplicateRowsORFLSMode(t *testing.T) {
	ctx := WithStandardActionInternalAccessScopes(context.Background(), "sa_read", []StandardActionInternalAccessScope{
		{StandardActionID: "sa_read", ObjectAPIName: "Task", Operation: PermRead},
		{StandardActionID: "sa_read", ObjectAPIName: "Task", Operation: PermRead, EnforceFLS: true},
	})

	if !IsScopedInternalAccess(ctx, "Task", PermRead) {
		t.Fatal("expected duplicate scoped rows to still grant scoped access")
	}
	if !ScopedInternalAccessEnforcesFLS(ctx, "Task", PermRead) {
		t.Fatal("duplicate rows must preserve FLS if any matching row opts in")
	}
	if ScopedInternalAccessBypassesFLS(ctx, "Task", PermRead) {
		t.Fatal("duplicate rows with any EnforceFLS=true entry must not bypass FLS")
	}
}

func TestWithoutStandardActionInternalAccessScopes_StripsStampedScopes(t *testing.T) {
	ctx := WithStandardActionInternalAccessScopes(context.Background(), "sa_convertlead", []StandardActionInternalAccessScope{
		{StandardActionID: "sa_convertlead", ObjectAPIName: "Task", Operation: PermEdit},
	})
	if !HasStandardActionInternalAccessScopes(ctx) {
		t.Fatal("expected stamped standard-action internal scopes")
	}

	stripped := WithoutStandardActionInternalAccessScopes(ctx)
	if HasStandardActionInternalAccessScopes(stripped) {
		t.Fatal("expected standard-action internal scopes to be stripped")
	}
	if IsScopedInternalAccess(stripped, "Task", PermEdit) {
		t.Fatal("stripped context must not grant scoped internal access")
	}
	if ScopedInternalAccessBypassesFLS(stripped, "Task", PermEdit) || ScopedInternalAccessEnforcesFLS(stripped, "Task", PermEdit) {
		t.Fatal("stripped context must not retain scoped FLS policy")
	}
	if !HasStandardActionExecutionContext(stripped) {
		t.Fatal("stripping internal scopes must preserve the authorized standard-action execution context")
	}
}

func TestWithoutStandardActionExecutionContext_StripsActionIdentityAndRootFlow(t *testing.T) {
	ctx := WithStandardActionExecutionRootFlow(context.Background(), "sa_convertlead", "Std_ConvertLead")
	ctx = WithStandardActionInternalAccessScopes(ctx, "sa_convertlead", []StandardActionInternalAccessScope{
		{StandardActionID: "sa_convertlead", ObjectAPIName: "Lead", Operation: PermEdit},
	})
	ctx = WithStandardActionProtectedFlowExecution(ctx, "Std_ConvertLead")

	stripped := WithoutStandardActionExecutionContext(ctx)
	if HasStandardActionExecutionContext(stripped) {
		t.Fatal("expected standard-action execution context to be stripped")
	}
	if StandardActionExecutionActionID(stripped) != "" {
		t.Fatalf("StandardActionExecutionActionID = %q, want empty", StandardActionExecutionActionID(stripped))
	}
	if StandardActionExecutionOwnsRootFlow(stripped, "Std_ConvertLead") {
		t.Fatal("expected root-flow ownership to be stripped")
	}
	if HasStandardActionInternalAccessScopes(stripped) || IsScopedInternalAccess(stripped, "Lead", PermEdit) {
		t.Fatal("execution identity stripping must make internal scopes unusable")
	}
	if !HasStandardActionProtectedFlowExecution(stripped) {
		t.Fatal("execution identity stripping should not silently remove protected-flow marker")
	}
}

func TestStandardActionExecutionContext_DoesNotGrantInternalAccess(t *testing.T) {
	ctx := WithStandardActionExecutionContext(context.Background(), "sa_convertlead")
	if !HasStandardActionExecutionContext(ctx) {
		t.Fatal("expected standard-action execution context")
	}
	if HasStandardActionInternalAccessScopes(ctx) {
		t.Fatal("execution context alone must not grant internal access scopes")
	}
	if IsScopedInternalAccess(ctx, "Task", PermEdit) {
		t.Fatal("execution context alone must not grant scoped internal access")
	}
}

func TestStandardActionExecutionRefIsExplicitAndStrippedWithExecutionContext(t *testing.T) {
	ctx := WithStandardActionExecutionRef(context.Background(), "convertLead")
	if got := StandardActionExecutionRef(ctx); got != "convertLead" {
		t.Fatalf("action ref = %q", got)
	}
	if HasStandardActionExecutionContext(ctx) {
		t.Fatal("action ref alone must not manufacture execution identity")
	}
	if got := StandardActionExecutionRef(WithoutStandardActionExecutionContext(ctx)); got != "" {
		t.Fatalf("stripped action ref = %q", got)
	}
}

func TestStandardActionExecutionRootFlow_MatchesOnlyOwnedRoot(t *testing.T) {
	ctx := WithStandardActionExecutionRootFlow(context.Background(), "sa_convertlead", "Std_ConvertLead")
	if !StandardActionExecutionOwnsRootFlow(ctx, "std_convertlead") {
		t.Fatal("expected standard action context to own its root flow case-insensitively")
	}
	if StandardActionExecutionOwnsRootFlow(ctx, "Std_RelinkLeadChildren") {
		t.Fatal("standard action root must not match a different protected flow")
	}
	if HasStandardActionProtectedFlowExecution(ctx) {
		t.Fatal("root ownership alone must not mark nested protected-flow execution as authorized")
	}

	ctx = WithStandardActionProtectedFlowExecution(ctx, "Std_ConvertLead")
	if !HasStandardActionProtectedFlowExecution(ctx) {
		t.Fatal("expected protected-flow execution marker")
	}

	stripped := WithoutStandardActionProtectedFlowExecution(ctx)
	if HasStandardActionProtectedFlowExecution(stripped) {
		t.Fatal("expected protected-flow execution marker to be stripped")
	}
	if !StandardActionExecutionOwnsRootFlow(stripped, "Std_ConvertLead") {
		t.Fatal("stripping protected-flow marker must preserve the standard-action root ownership context")
	}
}
