//go:build crm

package crm

// Salesforce REST API v63.0 error wire vocabulary.
//
// These symbols are the L1-owned Salesforce v63 error wire shape. They formerly
// lived in the app-blind L0 kernel package nexuscrm-kernel/pkg/apierr; PR-6 of
// the L0-B carve relocated them here so the kernel holds only neutral error
// types and the Salesforce error dialect is owned by the CRM distribution.
//
// Salesforce returns errors as a JSON array of objects, not a single object.

// SFError represents a Salesforce-compatible error (must be wrapped in array).
type SFError struct {
	ErrorCode string   `json:"errorCode"`
	Message   string   `json:"message"`
	Fields    []string `json:"fields,omitempty"`
}

const SFGenericInternalErrorMessage = "An internal server error occurred. Contact your system administrator."

// SFErrorResponse returns a Salesforce-compatible error array.
// Usage: c.JSON(status, SFErrorResponse("NOT_FOUND", "Resource not found"))
func SFErrorResponse(errorCode, message string) []SFError {
	return []SFError{{ErrorCode: errorCode, Message: message}}
}

func SFGenericInternalErrorResponse() []SFError {
	return SFErrorResponse(SFCodeInternalError, SFGenericInternalErrorMessage)
}

// SFErrorWithFields returns a Salesforce-compatible error array with field names.
// Usage: c.JSON(status, SFErrorWithFields("REQUIRED_FIELD_MISSING", "Required fields", "Name", "Email"))
func SFErrorWithFields(errorCode, message string, fields ...string) []SFError {
	return []SFError{{ErrorCode: errorCode, Message: message, Fields: fields}}
}

// Standard Salesforce Error Codes (for consistency)
const (
	SFCodeUnauthorized                   = "UNAUTHORIZED"
	SFCodeForbidden                      = "FORBIDDEN"
	SFCodeNotFound                       = "NOT_FOUND"
	SFCodeConflict                       = "CONFLICT"
	SFCodeInvalidRequest                 = "INVALID_REQUEST"
	SFCodeInvalidField                   = "INVALID_FIELD"
	SFCodeInvalidQuery                   = "INVALID_QUERY"
	SFCodeMalformedQuery                 = "MALFORMED_QUERY"
	SFCodeJSONParserError                = "JSON_PARSER_ERROR"
	SFCodeRequiredFieldMissing           = "REQUIRED_FIELD_MISSING"
	SFCodeLimitExceeded                  = "LIMIT_EXCEEDED"
	SFCodeExceededIDLimit                = "EXCEEDED_ID_LIMIT"
	SFCodeUnknownException               = "UNKNOWN_EXCEPTION"
	SFCodeMissingQuery                   = "MISSING_QUERY"
	SFCodeInvalidLocator                 = "INVALID_LOCATOR"
	SFCodeInvalidQueryLocator            = "INVALID_QUERY_LOCATOR"
	SFCodeInvalidSessionID               = "INVALID_SESSION_ID"
	SFCodeMalformedSearch                = "MALFORMED_SEARCH"
	SFCodeMissingOAuthToken              = "Missing_OAuth_Token"
	SFCodeInsertFailed                   = "INSERT_FAILED"
	SFCodeUpdateFailed                   = "UPDATE_FAILED"
	SFCodeDeleteFailed                   = "DELETE_FAILED"
	SFCodeUpsertFailed                   = "UPSERT_FAILED"
	SFCodeFieldCustomValidationException = "FIELD_CUSTOM_VALIDATION_EXCEPTION"
	SFCodeInvalidCrossReferenceKey       = "INVALID_CROSS_REFERENCE_KEY"
	// SFCodeInvalidFieldForInsertUpdate is the SF v63.0 error code emitted when a
	// payload contains a field the caller cannot write due to user-level FLS
	// Edit denial, or a handful of explicit immutable-field rejection paths
	// (e.g. CreatedDate on update). Intrinsically non-writable fields
	// (formula, auto-number, system-managed) are silently dropped by the
	// current write paths rather than surfaced with this code. Verified
	// against real SF sandbox.
	SFCodeInvalidFieldForInsertUpdate = "INVALID_FIELD_FOR_INSERT_UPDATE"
	// SFCodeAllOrNoneOperationRolledBack is the per-record statusCode SF emits
	// for records that would have succeeded in a composite collections write
	// but were rolled back because a sibling record failed under allOrNone=true.
	// Verified against SF sandbox for DELETE/PATCH on /composite/sobjects.
	SFCodeAllOrNoneOperationRolledBack = "ALL_OR_NONE_OPERATION_ROLLED_BACK"
	// SFCodeProcessingHalted is the generic per-record statusCode SF uses when
	// a composite collections record hit a non-specific processing error
	// (not an FLS / not-found / invalid-id case). Used as the fallback in
	// bulkErrorEntry when no more specific code applies.
	SFCodeProcessingHalted = "PROCESSING_HALTED"
	SFCodeQueryFailed      = "QUERY_FAILED"
	SFCodeInternalError    = "INTERNAL_ERROR"
	// SFCodeFieldIntegrityException is the SF v63.0 error code for save failures
	// caused by the current field state, such as a required parent field being
	// null when an autonumber format references it. SF returns this as HTTP 400.
	SFCodeFieldIntegrityException = "FIELD_INTEGRITY_EXCEPTION"
	// Bulk API specific error codes
	SFCodeInvalidJobState   = "INVALID_JOB_STATE"
	SFCodeJobCreationFailed = "JOB_CREATION_FAILED"
	SFCodeJobNotFound       = "JOB_NOT_FOUND"
	SFCodeNoQuery           = "NO_QUERY"
	SFCodeInvalidObject     = "INVALID_OBJECT"
	SFCodeInvalidOperation  = "INVALID_OPERATION"
	SFCodeInsufficientPerms = "INSUFFICIENT_PERMISSIONS"
	SFCodeFileTooLarge      = "FILE_TOO_LARGE"
	// SFCodeUnableToLockRow is the SF v63.0 error code emitted when a record
	// cannot be locked due to concurrent modification. Clients may retry.
	SFCodeUnableToLockRow = "UNABLE_TO_LOCK_ROW"
)
