package audit

import (
	"strings"

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

// AllowedHistoryFieldNames derives the positive FieldName allow-list for the
// public <Object>History virtual view from object metadata plus caller FLS.
func AllowedHistoryFieldNames(schema *models.ObjectMetadata, perms UserPermissions) ([]string, error) {
	if schema == nil {
		return []string{}, nil
	}
	allowed := make([]string, 0)
	allowedSet := make(map[string]struct{})
	addAllowed := func(fieldName string) {
		fieldName = strings.TrimSpace(fieldName)
		if fieldName == "" {
			return
		}
		if _, exists := allowedSet[fieldName]; exists {
			return
		}
		allowedSet[fieldName] = struct{}{}
		allowed = append(allowed, fieldName)
	}
	ownerIDReadable := false
	for _, field := range schema.Fields {
		fieldName := strings.TrimSpace(field.APIName)
		if fieldName == "" {
			continue
		}
		isOwnerID := strings.EqualFold(fieldName, constants.FieldOwnerID)
		readable, err := CheckFLSReadAccess(perms, schema.APIName, fieldName)
		if err != nil {
			return nil, err
		}
		if isOwnerID && readable {
			ownerIDReadable = true
		}
		if readable {
			// Temporal eligibility is owned by the interval ledger rather than
			// the field's current TrackHistory flag. Keeping every live,
			// FLS-readable metadata field in this positive list allows closed
			// historical intervals to remain visible after disable while the SQL
			// interval predicate still rejects never-tracked facts.
			addAllowed(fieldName)
		}
	}

	// Audit state-transition rows are public <Object>History pseudo-fields, not
	// _System_Field metadata rows. They carry no field payload, so TrackHistory
	// does not apply; keep them in the positive list through shared audit constants.
	addAllowed(FieldNameCreated)
	addAllowed(FieldNameDeleted)
	addAllowed(FieldNameUndeleted)
	addAllowed(FieldNameLocked)
	addAllowed(FieldNameUnlocked)
	if ownerIDReadable {
		addAllowed(FieldNameOwner)
	}
	return allowed, nil
}
