package models

import "github.com/nexuscrm/shared/pkg/constants"

// RowVisibilityKind is the app-blind classification of an object's row-visibility
// policy. Enforcement paths dispatch on this instead of branching on the
// dialect-specific constants.SharingModel* tokens directly (L0-D D1).
type RowVisibilityKind int

const (
	// RowVisibilityPrivate is the default: rows are visible only through
	// ownership / role-hierarchy / sharing grants (also the fallback for empty
	// or unknown sharing models).
	RowVisibilityPrivate RowVisibilityKind = iota
	// RowVisibilityPublicRead grants every user read on every row.
	RowVisibilityPublicRead
	// RowVisibilityPublicReadWrite grants every user read+write on every row.
	RowVisibilityPublicReadWrite
	// RowVisibilityParentControlled derives row access from a parent record.
	RowVisibilityParentControlled
	// RowVisibilityFolderScoped derives row access from a folder — either the
	// row's own folder (FolderScopeField == "" ⇒ the record Id) or a folder
	// referenced by a scope column (FolderScopeField == "FolderId").
	RowVisibilityFolderScoped
)

// RowVisibilityPolicy is the neutral row-visibility descriptor produced by
// RowVisibilityFor. It is a pure classification: it carries no metadata
// lookups, no DB handles, and no behavior.
type RowVisibilityPolicy struct {
	// Kind is the app-blind visibility classification.
	Kind RowVisibilityKind
	// FolderScopeField names the column that references the governing folder for
	// RowVisibilityFolderScoped policies. "" means the record's own Id is the
	// folder subject; "FolderId" means the row is scoped by its FolderId column.
	// Unused (empty) for every other Kind.
	FolderScopeField string
	// HierarchyGranted mirrors ObjectMetadata.EnableHierarchySharing. It is only
	// consulted by the owner-visibility suffix (role-hierarchy grant-up); it is
	// harmless on every other Kind.
	HierarchyGranted bool
}

// RowVisibilityFor is the ONE app-blind SharingModel->neutral-policy translation
// point (L0-D D1). Enforcement dispatches on the returned RowVisibilityKind and
// must NOT branch on constants.SharingModel* directly. The SharingModel switch is
// confined here (D6-allowlisted). Pure: no metadata lookups, no DB, no behavior.
func RowVisibilityFor(schema *ObjectMetadata) RowVisibilityPolicy {
	// nil is handled upstream at rls_filter.go:61 denyAll before this is called;
	// classify defensively as Private so a stray nil never widens visibility.
	if schema == nil {
		return RowVisibilityPolicy{Kind: RowVisibilityPrivate}
	}

	hierarchyGranted := schema.EnableHierarchySharing

	switch schema.SharingModel {
	case constants.SharingModelPublicRead:
		return RowVisibilityPolicy{Kind: RowVisibilityPublicRead, HierarchyGranted: hierarchyGranted}
	case constants.SharingModelPublicReadWrite:
		return RowVisibilityPolicy{Kind: RowVisibilityPublicReadWrite, HierarchyGranted: hierarchyGranted}
	case constants.SharingModelControlledByParent:
		return RowVisibilityPolicy{Kind: RowVisibilityParentControlled, HierarchyGranted: hierarchyGranted}
	case constants.SharingModelFolderSharing:
		return RowVisibilityPolicy{Kind: RowVisibilityFolderScoped, FolderScopeField: "", HierarchyGranted: hierarchyGranted}
	case constants.SharingModelFolderContentSharing:
		return RowVisibilityPolicy{Kind: RowVisibilityFolderScoped, FolderScopeField: "FolderId", HierarchyGranted: hierarchyGranted}
	default:
		// Private / empty / unknown all collapse to the ownership-gated default.
		return RowVisibilityPolicy{Kind: RowVisibilityPrivate, HierarchyGranted: hierarchyGranted}
	}
}
