package constants

import "strings"

// SystemTablePrefix is the prefix for all system tables
const (
	SystemTablePrefix = "_System_"

	// SystemFieldPrefix is the prefix for all system fields (Empty for Native PascalCase)
	SystemFieldPrefix = ""

	// UniqueIndexPrefix is the prefix for unique indexes
	UniqueIndexPrefix = "uniq_"

	// DefaultTableOptions defines the standard engine and charset for all tables
	DefaultTableOptions = "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"

	// TableNamePattern is the regex for valid table names (PascalCase/snake_case)
	// Salesforce Compatibility: Allow Uppercase
	TableNamePattern = `^[a-zA-Z_][a-zA-Z0-9_]*$`

	// FieldNamePattern is the regex for valid field names (PascalCase/snake_case)
	FieldNamePattern = `^[a-zA-Z_][a-zA-Z0-9_]*$`

	FieldProfilePermission_ProfileID         = "ProfileId"
	FieldProfilePermission_PermissionAPIName = "PermissionApiName"
	FieldProfilePermission_IsEnabled         = "IsEnabled"

	FieldPermissionSetPermission_PermissionSetID   = "PermissionSetId"
	FieldPermissionSetPermission_PermissionAPIName = "PermissionApiName"
	FieldPermissionSetPermission_IsEnabled         = "IsEnabled"
)

// IsSystemTable checks if a table name is a system table
func IsSystemTable(tableName string) bool {
	return strings.HasPrefix(tableName, SystemTablePrefix)
}

// IsManagedSystemTable checks whether a table is part of the platform-managed
// system substrate, including Salesforce-compatible setup tables without the
// _System_ prefix such as permissions and user metadata.
//
// Both checks are CASE-INSENSITIVE. This function is a destructive-operation
// guard (e.g. the DeleteSchema orphan-reconcile refuses to DropTable a managed
// substrate table). Callers may pass a name that upstream routing already
// lowercased, while the canonical name is mixed-case (`_System_InstalledPack`,
// `ObjectPermissions`). A case-sensitive prefix check would let a lowercased
// `_system_installedpack` slip past into a DROP TABLE that TiDB (with
// lower_case_table_names=2) then resolves to the real table. Case-insensitive
// matching on BOTH the prefix and the managed list closes that gap (#3484).
func IsManagedSystemTable(tableName string) bool {
	if strings.HasPrefix(strings.ToLower(tableName), strings.ToLower(SystemTablePrefix)) {
		return true
	}
	for _, systemTable := range AllSystemTableNames {
		if strings.EqualFold(systemTable, tableName) {
			return true
		}
	}
	return false
}

// GetSystemFieldNames returns the list of system fields that every table should have.
// Note: id is NOT required since some tables use different primary keys (key_name, composite keys).
func GetSystemFieldNames() []string {
	// Only temporal fields are universally required for operation tracking
	return []string{
		FieldCreatedDate,
		FieldLastModifiedDate,
	}
}

// StandardSystemFields returns the list of standard system field names
// that are platform-injected on record-typed business objects.
func StandardSystemFields() []string {
	return []string{
		FieldID,
		FieldOwnerID,
		FieldCreatedDate,
		FieldCreatedByID,
		FieldLastModifiedDate,
		FieldLastModifiedByID,
		FieldIsDeleted,
		FieldSystemModstamp,
	}
}

// IsSystemField checks if a field name is a standard system field
func IsSystemField(fieldName string) bool {
	if fieldName == FieldRecordTypeID {
		return true
	}
	for _, sf := range StandardSystemFields() {
		if sf == fieldName {
			return true
		}
	}
	return false
}
