package analytics

import (
	"reflect"
	"testing"

	domainrls "github.com/nexuscrm/kernel/pkg/rls"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

// PR-D0a capture-and-freeze goldens for the "under-counted third branch": the
// SharingModel OWD reimplementation used by the SystemContext targetRecordRead
// bypass path in query_clause_fls.go.
//
// These pins encode CURRENT behavior of the code as-is. They anchor the silent
// OWD reimplementation in queryParentFilterBypassTargetRecordSchemaUnrestricted
// (query_clause_fls.go:633) that D1 must unify with the canonical OWD arm in
// nexuscrm-permissions/rls_filter.go:156-159, plus the lowering of the fabricated
// bypass Result through queryParentFilterVisibilityPlanFromRLS
// (query_clause_fls.go:465).
//
// Scope note (see also the limitations reported for D0a): the focus branch only
// fires under SystemContext + a targetRecordRead RowReadPolicy (not ordinary user
// queries), and is a read-only-by-construction reimplementation of the OWD arm
// (there is no operation input). The two direct-call pins below (the pure OWD
// predicate and the plan lowering) are sufficient for D0a; a full end-to-end
// QueryWithSpec assertion is not required to freeze this behavior.

// TestQueryParentFilterBypassTargetRecordSchemaUnrestrictedGolden freezes the
// pure OWD-reimplementation predicate over every SharingModel and over the three
// AccessPolicy shapes {nil, RowRead-set, derived}. No mocks.
//
// Captured truth of query_clause_fls.go:633-639:
//   - schema == nil                              -> false
//   - schema.UsesDerivedAccessPolicy() (derived) -> false (gate, regardless of model)
//   - schema.RowReadPolicy() != nil (RowRead set)-> false (gate, regardless of model)
//   - otherwise: PublicRead / PublicReadWrite    -> true
//   - otherwise: everything else                 -> false
func TestQueryParentFilterBypassTargetRecordSchemaUnrestrictedGolden(t *testing.T) {
	// nilPtr forces the nil-schema arm of the predicate.
	var nilSchema *models.ObjectMetadata

	if got := queryParentFilterBypassTargetRecordSchemaUnrestricted(nilSchema); got != false {
		t.Fatalf("nil schema: got %v, want false", got)
	}

	sharingModels := []constants.SharingModel{
		constants.SharingModelPrivate,
		constants.SharingModelPublicRead,
		constants.SharingModelPublicReadWrite,
		constants.SharingModelControlledByParent,
		constants.SharingModelFolderSharing,
		constants.SharingModelFolderContentSharing,
	}

	// AccessPolicy shape variants exercised per SharingModel.
	type accessShape struct {
		name   string
		policy *models.ObjectAccessPolicy
		// unrestrictedWhenPublic reports whether, for a Public* model, this shape
		// still returns true. For non-Public models the expected result is always
		// false regardless of shape.
		unrestrictedWhenPublic bool
	}
	shapes := []accessShape{
		{name: "nil-access-policy", policy: nil, unrestrictedWhenPublic: true},
		// A non-derived policy with RowRead set trips the RowReadPolicy()!=nil gate.
		{
			name: "rowread-set",
			policy: &models.ObjectAccessPolicy{
				RowRead: &models.RowReadPolicy{Kind: "targetRecordRead"},
			},
			unrestrictedWhenPublic: false,
		},
		// A derived policy (no RowRead) trips the UsesDerivedAccessPolicy() gate.
		{
			name:                   "derived",
			policy:                 &models.ObjectAccessPolicy{Mode: "derived"},
			unrestrictedWhenPublic: false,
		},
	}

	isPublic := func(m constants.SharingModel) bool {
		return m == constants.SharingModelPublicRead || m == constants.SharingModelPublicReadWrite
	}

	for _, m := range sharingModels {
		for _, s := range shapes {
			t.Run(string(m)+"/"+s.name, func(t *testing.T) {
				schema := &models.ObjectMetadata{
					APIName:      "BypassTarget",
					SharingModel: m,
					AccessPolicy: s.policy,
				}
				want := isPublic(m) && s.unrestrictedWhenPublic
				got := queryParentFilterBypassTargetRecordSchemaUnrestricted(schema)
				if got != want {
					t.Fatalf("SharingModel=%q shape=%q: got %v, want %v", m, s.name, got, want)
				}
			})
		}
	}
}

// bypassGoldenSchemaWithOwner builds a schema carrying a physical OwnerId column,
// mirroring the proven owner-arm fixtures elsewhere in this package (e.g. the
// TargetRecord owner-visibility tests). Used only to lower an owner-scoped RLS
// Result; SharingModel here is irrelevant to the plan lowering.
func bypassGoldenSchemaWithOwner() *models.ObjectMetadata {
	return &models.ObjectMetadata{
		APIName:      "BypassTarget",
		SharingModel: constants.SharingModelPrivate,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldOwnerID, Type: constants.FieldTypeReference, PhysicalName: "owner_id", IsSystem: true},
		},
	}
}

// TestQueryParentFilterVisibilityPlanFromRLSSkipGolden freezes the lowering of
// the exact Result the bypass fabricates for an unrestricted target:
// Result{Skip:true} -> the zero (empty / no-filter) plan. Direct call, no mocks.
func TestQueryParentFilterVisibilityPlanFromRLSSkipGolden(t *testing.T) {
	schema := bypassGoldenSchemaWithOwner()
	result := &domainrls.Result{ObjectAPIName: "BypassTarget", Skip: true}

	plan, err := queryParentFilterVisibilityPlanFromRLS(
		schema, result, "FilterExpr", "BypassTarget", false,
		queryParentFilterTargetRecordVisibilityMaxDepth, make(map[string]bool),
	)
	if err != nil {
		t.Fatalf("Skip result: unexpected error = %v", err)
	}
	if !reflect.DeepEqual(plan, queryParentFilterVisibilityPlan{}) {
		t.Fatalf("Skip result: got plan %+v, want empty (zero-value) plan", plan)
	}
	if plan.denyAll {
		t.Fatalf("Skip result: denyAll = true, want false")
	}
}

// TestQueryParentFilterVisibilityPlanFromRLSDenyAllGolden freezes the lowering of
// Result{DenyAll:true} -> a denyAll plan (and nothing else set). Direct call.
func TestQueryParentFilterVisibilityPlanFromRLSDenyAllGolden(t *testing.T) {
	schema := bypassGoldenSchemaWithOwner()
	result := &domainrls.Result{ObjectAPIName: "BypassTarget", DenyAll: true}

	plan, err := queryParentFilterVisibilityPlanFromRLS(
		schema, result, "FilterExpr", "BypassTarget", false,
		queryParentFilterTargetRecordVisibilityMaxDepth, make(map[string]bool),
	)
	if err != nil {
		t.Fatalf("DenyAll result: unexpected error = %v", err)
	}
	want := queryParentFilterVisibilityPlan{denyAll: true}
	if !reflect.DeepEqual(plan, want) {
		t.Fatalf("DenyAll result: got plan %+v, want %+v", plan, want)
	}
}

// TestQueryParentFilterVisibilityPlanFromRLSOwnerArmGolden freezes the lowering of
// an owner-scoped Result (HasOwnerField + OwnerUserIDs) into the owner-scoped
// plan: the OwnerId physical column is resolved and the owner user IDs are carried
// through, with no other arm populated and denyAll=false. Direct call.
func TestQueryParentFilterVisibilityPlanFromRLSOwnerArmGolden(t *testing.T) {
	schema := bypassGoldenSchemaWithOwner()
	result := &domainrls.Result{
		ObjectAPIName: "BypassTarget",
		HasOwnerField: true,
		OwnerUserIDs:  []string{"005-reader"},
	}

	plan, err := queryParentFilterVisibilityPlanFromRLS(
		schema, result, "FilterExpr", "BypassTarget", false,
		queryParentFilterTargetRecordVisibilityMaxDepth, make(map[string]bool),
	)
	if err != nil {
		t.Fatalf("owner-arm result: unexpected error = %v", err)
	}
	want := queryParentFilterVisibilityPlan{
		ownerPhysicalName: "owner_id",
		ownerUserIDs:      []string{"005-reader"},
	}
	if !reflect.DeepEqual(plan, want) {
		t.Fatalf("owner-arm result: got plan %+v, want %+v", plan, want)
	}
	if plan.denyAll {
		t.Fatalf("owner-arm result: denyAll = true, want false")
	}
}
