package metadata

import (
	"context"
	"log"
	"strings"

	"github.com/nexuscrm/shared/pkg/models"
)

// GetParentControlledObject returns the parent object's APIName when `schema`
// is a `ControlledByParent` child with a configured sharing-parent relationship.
// Returns "" otherwise (including for malformed metadata that declares
// `ControlledByParent` without a matching `IsSharingParent` relationship row).
//
// This is the single SSoT predicate consumed by every layer that needs to ask
// "is this object parent-controlled?" — runtime non-record CRUD, runtime
// record-aware CRUD, preflight deferral, seeder/reconcile scope, and the SQL
// drift verifier (the SQL form is an EXISTS subquery against
// `_System_Relationship.IsSharingParent`). Two-part predicate:
//
//   - schema.SharingModel == SharingModelControlledByParent
//   - GetSharingParentRelationship(schema.APIName) != nil
func (ms *MetadataService) GetParentControlledObject(ctx context.Context, schema *models.ObjectMetadata) string {
	if schema == nil {
		return ""
	}
	// L0-D D1: classify via the app-blind translation point instead of branching
	// on constants.SharingModel* directly. The GetSharingParentRelationship
	// resolution below (the actual parent-shape lookup) is unchanged.
	if models.RowVisibilityFor(schema).Kind != models.RowVisibilityParentControlled {
		return ""
	}
	rel := ms.GetSharingParentRelationship(ctx, schema.APIName)
	if rel == nil {
		return ""
	}
	return rel.ParentObjectAPIName
}

// GetSharingParentRelationship returns the persisted relationship row that
// marks a child object as ControlledByParent. This keeps sharing-parent shape
// resolution inside metadata service so permission paths do not scan the
// relationship graph independently.
func (ms *MetadataService) GetSharingParentRelationship(ctx context.Context, childObjectAPIName string) *models.Relationship {
	if ms.UsesRequestBoundRuntimeView() {
		view, ok := ms.runtimeView(ctx)
		if !ok || view == nil {
			return nil
		}
		relationship, _ := view.SharingParentRelationship(childObjectAPIName)
		return relationship
	}
	if err := ms.ensureCoreCacheInitialized(ctx); err != nil {
		log.Printf("⚠️ Failed to initialize core cache in GetSharingParentRelationship(%s): %v", childObjectAPIName, err)
		return nil
	}

	snap := ms.loadCoreCache()
	if snap == nil {
		return nil
	}

	for _, rel := range snap.relationshipsMap[strings.ToLower(childObjectAPIName)] {
		if rel == nil {
			continue
		}
		if !rel.IsSharingParent {
			continue
		}
		if !strings.EqualFold(rel.ChildObjectAPIName, childObjectAPIName) {
			continue
		}
		return rel
	}

	return nil
}
