package files

import (
	"context"
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/nexuscrm/kernel/pkg/utils"
	"github.com/nexuscrm/metadata"
	"github.com/nexuscrm/persistence"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/contract"
	sharederrors "github.com/nexuscrm/shared/pkg/errors"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/nexuscrm/storage"
)

type fileRecordStore interface {
	Insert(ctx context.Context, objectName string, data models.SObject, currentUser *models.UserSession) (models.SObject, error)
	Retrieve(ctx context.Context, objectName string, id string, user *models.UserSession) (models.SObject, error)
	GetRaw(ctx context.Context, objectName string, id string) (models.SObject, error)
	Update(ctx context.Context, objectName string, id string, updates models.SObject, currentUser *models.UserSession) error
}

type filePermissionChecker interface {
	CheckPermissionOrErrorWithUser(ctx context.Context, objectAPIName string, operation string, user *models.UserSession) error
}

type DetachedReferenceResolver func(reference string) (contract.FileBlobReference, bool)

type DetachedReferenceResolverRegistration struct {
	SourceType string
	Resolver   DetachedReferenceResolver
}

type UploadOperationJournal interface {
	Accept(context.Context, persistence.FileUploadOperationAcceptance) (persistence.FileUploadOperation, bool, error)
	Load(context.Context, string) (persistence.FileUploadOperation, error)
	MarkBlobStored(context.Context, string, string, string, string, string, time.Time) error
	MarkCompleted(context.Context, string, string, string, string, time.Time) error
	FinalizeBlobStored(context.Context, string, string, string, string, time.Time, func(context.Context) error) error
}

type ContractServiceOption func(*ContractService)

// WithoutLegacyFileFallback closes filesystem compatibility reads for a new
// serving composition. Existing monolith compositions retain their current
// behavior unless they opt in, so production routing and legacy deployment are
// unchanged while a D3 candidate can prove zero fallback.
func WithoutLegacyFileFallback() ContractServiceOption {
	return func(s *ContractService) {
		s.allowLegacyFileFallback = false
	}
}

// WithDurableUploadJournal installs the sole upload-operation authority used
// by the private Runtime composition. Legacy compositions that do not opt in
// keep their existing behavior and cannot accidentally masquerade as the M1
// Files capability.
func WithDurableUploadJournal(store UploadOperationJournal) ContractServiceOption {
	return func(s *ContractService) {
		if store == nil {
			panic("files: durable upload journal is required")
		}
		s.uploadOperations = store
	}
}

func WithDetachedReferenceResolver(sourceType string, resolver DetachedReferenceResolver) ContractServiceOption {
	return WithDetachedReferenceResolvers(DetachedReferenceResolverRegistration{
		SourceType: sourceType,
		Resolver:   resolver,
	})
}

func WithDetachedReferenceResolvers(registrations ...DetachedReferenceResolverRegistration) ContractServiceOption {
	return func(s *ContractService) {
		if len(registrations) == 0 {
			return
		}
		if s.detachedReferenceResolvers == nil {
			s.detachedReferenceResolvers = map[string]DetachedReferenceResolver{}
		}
		for _, registration := range registrations {
			sourceType := normalizeDetachedReferenceSourceType(registration.SourceType)
			if sourceType == "" {
				panic("files: detached reference resolver requires sourceType")
			}
			if registration.Resolver == nil {
				panic("files: detached reference resolver requires resolver")
			}
			if _, exists := s.detachedReferenceResolvers[sourceType]; exists {
				panic(fmt.Sprintf("files: duplicate detached reference resolver for sourceType %q", registration.SourceType))
			}
			s.detachedReferenceResolvers[sourceType] = registration.Resolver
		}
	}
}

func WithStorageAuthorityCatalog(catalog *storage.AuthorityCatalog) ContractServiceOption {
	return func(s *ContractService) {
		if catalog == nil {
			panic("files: storage authority catalog is required")
		}
		s.storageAuthorities = catalog
	}
}

// recordAttachmentMetadataAuthorizer owns the storage-free authorization and
// immutable metadata projection shared by enqueue and file delivery.
type recordAttachmentMetadataAuthorizer struct {
	records     fileRecordStore
	permissions filePermissionChecker
	metadata    *metadata.MetadataService
}

// NewRecordAttachmentMetadataAuthorizer builds the storage-free authority used
// when a caller needs to authorize and freeze _System_File metadata but must
// not open the backing blob. The full ContractService embeds this same owner,
// keeping one metadata authorization implementation for enqueue and delivery.
func NewRecordAttachmentMetadataAuthorizer(
	records fileRecordStore,
	permissions filePermissionChecker,
	metadataSvc *metadata.MetadataService,
) (contract.RecordAttachmentMetadataAuthorizer, error) {
	if records == nil || permissions == nil {
		return nil, errors.New("file attachment metadata authorizer requires records and permissions")
	}
	return &recordAttachmentMetadataAuthorizer{
		records: records, permissions: permissions, metadata: metadataSvc,
	}, nil
}

// ContractService is the neutral file/blob surface used by dialect modules. It
// keeps storage provider selection, _System_File metadata writes, and parent
// authorization below the dialect boundary.
type ContractService struct {
	*recordAttachmentMetadataAuthorizer
	store                      storage.ObjectStore
	legacyUploadRoot           string
	storageProvider            string
	storageBucket              string
	storageAuthorityDigest     string
	storageAuthorities         *storage.AuthorityCatalog
	resolveStore               func(storage.Config) (storage.ObjectStore, error)
	detachedReferenceResolvers map[string]DetachedReferenceResolver
	allowLegacyFileFallback    bool
	uploadOperations           UploadOperationJournal
}

func NewContractService(
	store storage.ObjectStore,
	storageProvider string,
	storageBucket string,
	legacyUploadRoot string,
	records fileRecordStore,
	permissions filePermissionChecker,
	metadataSvc *metadata.MetadataService,
	opts ...ContractServiceOption,
) *ContractService {
	if store == nil {
		panic("file contract service requires a storage provider")
	}
	storageProvider = strings.TrimSpace(storageProvider)
	if storageProvider == "" {
		storageProvider = storage.ProviderFilesystem
	}
	storageBucket = strings.TrimSpace(storageBucket)
	if strings.EqualFold(storageProvider, storage.ProviderFilesystem) && storageBucket == "" {
		storageBucket = storage.DefaultFilesystemBucket
	}
	legacyUploadRoot = strings.TrimSpace(legacyUploadRoot)
	if legacyUploadRoot == "" {
		legacyUploadRoot = storage.LoadConfigFromEnv().LegacyUploadRoot
	}
	storageConfig := storage.LoadConfigFromEnv()
	storageConfig.Provider = storageProvider
	storageConfig.Bucket = storageBucket
	storageAuthorityDigest, _ := storage.ConfigAuthorityDigest(storageConfig)
	svc := &ContractService{
		recordAttachmentMetadataAuthorizer: &recordAttachmentMetadataAuthorizer{
			records: records, permissions: permissions, metadata: metadataSvc,
		},
		store:                   store,
		legacyUploadRoot:        legacyUploadRoot,
		storageProvider:         storageProvider,
		storageBucket:           storageBucket,
		storageAuthorityDigest:  storageAuthorityDigest,
		resolveStore:            storage.NewStore,
		allowLegacyFileFallback: true,
	}
	for _, opt := range opts {
		if opt != nil {
			opt(svc)
		}
	}
	return svc
}

func (s *ContractService) StoreDetachedFile(ctx context.Context, req contract.FileUploadRequest) (*contract.FileUploadResult, error) {
	if err := s.authorizeFileCreate(ctx, req.User); err != nil {
		return nil, err
	}
	fileID := strings.TrimSpace(req.ID)
	if fileID == "" {
		return nil, sharederrors.NewMalformedRequestError("missing detached file id")
	}
	objectKey := strings.TrimSpace(req.StorageKey)
	if objectKey == "" {
		return nil, sharederrors.NewMalformedRequestError("missing detached file storage key")
	}

	meta, err := s.store.PutObject(ctx, objectKey, req.Body, storage.PutObjectOptions{
		ContentType:   req.ContentType,
		ContentLength: &req.ContentLength,
	})
	if err != nil {
		return nil, err
	}

	return &contract.FileUploadResult{
		ID:   fileID,
		Name: sanitizeUploadedFileName(req.FileName),
		Size: meta.Size,
		Mime: req.ContentType,
	}, nil
}

func (s *ContractService) StoreRecordAttachment(ctx context.Context, req contract.FileUploadRequest) (*contract.FileUploadResult, error) {
	if s.records == nil || s.permissions == nil {
		return nil, fmt.Errorf("record-file upload requires persistence and permissions dependencies")
	}

	parentObjectAPIName := NormalizeParentObjectAPIName(req.ParentID, req.ParentObjectAPIName, func(recordID string) (string, bool) {
		if s.metadata == nil {
			return "", false
		}
		return s.metadata.ResolveObjectForRecordID(ctx, recordID)
	})

	if err := s.permissions.CheckPermissionOrErrorWithUser(ctx, constants.TableFile, constants.PermCreate, req.User); err != nil {
		return nil, err
	}
	if err := s.authorizeParentAccess(ctx, parentObjectAPIName, req.ParentID, req.User); err != nil {
		return nil, err
	}
	if s.uploadOperations != nil {
		return s.storeRecordAttachmentDurable(ctx, req, parentObjectAPIName)
	}

	systemFileID := strings.TrimSpace(req.ID)
	if systemFileID == "" {
		systemFileID = utils.GenerateID()
	} else {
		existing, existingErr := s.records.GetRaw(ctx, constants.TableFile, systemFileID)
		if existingErr == nil && existing != nil {
			name, _ := existing[constants.FieldSysFile_OriginalFileName].(string)
			mime, _ := existing[constants.FieldSysFile_MimeType].(string)
			parentID, _ := existing[constants.FieldSysFile_ParentID].(string)
			parentObject, _ := existing[constants.FieldSysFile_ParentObjectAPIName].(string)
			checksum, _ := existing[constants.FieldSysFile_Checksum].(string)
			size, sizeOK := fileSizeBytes(existing[constants.FieldSysFile_SizeBytes])
			if name != sanitizeUploadedFileName(req.FileName) || mime != req.ContentType ||
				parentID != req.ParentID || parentObject != parentObjectAPIName ||
				!sizeOK || size != req.ContentLength {
				return nil, sharederrors.NewMalformedRequestError("file idempotency identity is bound to different content")
			}
			replayedChecksum, checksumErr := checksumFileBody(req.Body)
			if checksumErr != nil {
				return nil, checksumErr
			}
			if checksum == "" || checksum != replayedChecksum {
				return nil, sharederrors.NewMalformedRequestError("file idempotency identity is bound to different content")
			}
			return &contract.FileUploadResult{ID: systemFileID, Name: name, Size: size, Mime: mime}, nil
		}
		if existingErr != nil && !isMissingFileRecord(existingErr) {
			return nil, existingErr
		}
	}
	originalFileName := sanitizeUploadedFileName(req.FileName)
	objectKey := systemFileObjectKey(parentObjectAPIName, req.ParentID, systemFileID, originalFileName)

	hasher := sha256.New()
	meta, err := s.store.PutObject(ctx, objectKey, io.TeeReader(req.Body, hasher), storage.PutObjectOptions{
		ContentType:   req.ContentType,
		ContentLength: &req.ContentLength,
	})
	if err != nil {
		return nil, err
	}

	createCtx := constants.WithSecurityContext(ctx, constants.ServiceContext, fileMetadataWriteSecurityReason)
	record := models.SObject{
		constants.FieldID:                          systemFileID,
		constants.FieldSysFile_ParentID:            req.ParentID,
		constants.FieldSysFile_ParentObjectAPIName: parentObjectAPIName,
		constants.FieldSysFile_Name:                originalFileName,
		constants.FieldSysFile_OriginalFileName:    originalFileName,
		constants.FieldSysFile_Extension:           strings.TrimPrefix(req.Extension, "."),
		constants.FieldSysFile_MimeType:            req.ContentType,
		constants.FieldSysFile_SizeBytes:           meta.Size,
		constants.FieldSysFile_StoragePath:         objectKey,
		constants.FieldSysFile_StorageProvider:     s.storageProvider,
		constants.FieldSysFile_StorageBucket:       s.storageBucket,
		constants.FieldSysFile_StorageKey:          objectKey,
		constants.FieldSysFile_Status:              "Active",
		constants.FieldSysFile_SourceType:          systemFileSourceTypeNative,
		constants.FieldSysFile_AttachmentKind:      defaultRecordAttachmentKind,
		constants.FieldSysFile_Checksum:            "sha256:" + hex.EncodeToString(hasher.Sum(nil)),
	}
	if strings.TrimSpace(req.AttachmentKind) != "" {
		record[constants.FieldSysFile_AttachmentKind] = strings.TrimSpace(req.AttachmentKind)
	}

	if _, err := s.records.Insert(createCtx, constants.TableFile, record, req.User); err != nil {
		_ = s.cleanupStoredObject(ctx, record, objectKey)
		return nil, err
	}

	return &contract.FileUploadResult{
		ID:   systemFileID,
		Name: originalFileName,
		Size: meta.Size,
		Mime: req.ContentType,
	}, nil
}

type uploadInProgressError struct{}

func (*uploadInProgressError) Error() string            { return "file upload is already in progress" }
func (*uploadInProgressError) RetriableCondition() bool { return true }

type uploadRepairRequiredError struct{}

func (*uploadRepairRequiredError) Error() string {
	return "durable file blob requires scheduled repair"
}
func (*uploadRepairRequiredError) RetriableCondition() bool { return true }

const (
	durableUploadRetention     = 24 * time.Hour
	durableUploadShutdownGrace = time.Minute
)

func (s *ContractService) storeRecordAttachmentDurable(
	ctx context.Context,
	req contract.FileUploadRequest,
	parentObjectAPIName string,
) (*contract.FileUploadResult, error) {
	systemFileID := strings.TrimSpace(req.ID)
	if systemFileID == "" {
		return nil, sharederrors.NewMalformedRequestError("durable file upload requires a stable file id")
	}
	originalFileName := sanitizeUploadedFileName(req.FileName)
	logicalObjectKey := systemFileObjectKey(parentObjectAPIName, req.ParentID, systemFileID, originalFileName)
	ownerToken, err := newDurableUploadOwnerToken()
	if err != nil {
		return nil, err
	}
	objectKey := durableUploadAttemptObjectKey(logicalObjectKey, ownerToken)
	headerHash, err := durableUploadHeaderHash(req, parentObjectAPIName, logicalObjectKey)
	if err != nil {
		return nil, err
	}
	if !validSHA256Digest(s.storageAuthorityDigest) {
		return nil, errors.New("file storage authority is incomplete")
	}
	now := time.Now().UTC()
	leaseUntil := durableUploadLeaseUntil(ctx, now)
	acceptance := persistence.FileUploadOperationAcceptance{
		ID: systemFileID, IdempotencyKey: systemFileID, RequestHash: headerHash,
		OwnerToken: ownerToken, ObjectKey: objectKey, SystemFileID: systemFileID,
		StorageProvider: s.storageProvider, StorageBucket: s.storageBucket,
		StorageAuthorityDigest: s.storageAuthorityDigest,
		ParentID:               req.ParentID, ParentObjectAPIName: parentObjectAPIName,
		LeaseUntil: leaseUntil, Now: now,
	}
	existing, loadErr := s.uploadOperations.Load(ctx, acceptance.IdempotencyKey)
	switch {
	case loadErr == nil:
		if !persistence.FileUploadOperationMatchesIdentity(existing, acceptance) {
			return nil, sharederrors.NewMalformedRequestError(
				"file idempotency identity is bound to different content",
			)
		}
		return s.serveDurableUploadJournalRow(
			ctx, req, parentObjectAPIName, existing, headerHash,
		)
	case !errors.Is(loadErr, persistence.ErrFileUploadOperationNotFound):
		return nil, loadErr
	}
	if result, found, err := s.replayExistingDurableUploadResult(
		ctx, req, parentObjectAPIName, systemFileID,
	); err != nil || found {
		return result, err
	}
	row, owner, err := s.uploadOperations.Accept(ctx, acceptance)
	if errors.Is(err, persistence.ErrFileUploadOperationConflict) {
		return nil, sharederrors.NewMalformedRequestError("file idempotency identity is bound to different content")
	}
	if err != nil {
		return nil, err
	}
	if owner {
		return s.storeDurableUploadBlobAndMetadata(ctx, req, parentObjectAPIName, row, headerHash)
	}
	return s.serveDurableUploadJournalRow(
		ctx, req, parentObjectAPIName, row, headerHash,
	)
}

func (s *ContractService) serveDurableUploadJournalRow(
	ctx context.Context,
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	row persistence.FileUploadOperation,
	headerHash string,
) (*contract.FileUploadResult, error) {
	switch row.State {
	case persistence.FileUploadOperationPrepared, persistence.FileUploadOperationFailed:
		return nil, &uploadInProgressError{}
	case persistence.FileUploadOperationBlobStored:
		return s.reconcileDurableUpload(
			ctx, req, parentObjectAPIName, row, headerHash,
		)
	case persistence.FileUploadOperationCompleted:
		return s.replayCompletedDurableUpload(ctx, req, parentObjectAPIName, row, headerHash)
	default:
		return nil, fmt.Errorf("file upload journal contains unknown state %q", row.State)
	}
}

func (s *ContractService) storeDurableUploadBlobAndMetadata(
	ctx context.Context,
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	row persistence.FileUploadOperation,
	headerHash string,
) (*contract.FileUploadResult, error) {
	hasher := sha256.New()
	putCtx, cancelPut := durableUploadAttemptContext(ctx, row.ExpiresAt)
	defer cancelPut()
	meta, err := s.store.PutObject(putCtx, row.ObjectKey, io.TeeReader(req.Body, hasher), storage.PutObjectOptions{
		ContentType: req.ContentType, ContentLength: &req.ContentLength,
	})
	if err != nil {
		return nil, err
	}
	if meta.Size != req.ContentLength {
		return nil, fmt.Errorf("file object store committed size %d, want %d", meta.Size, req.ContentLength)
	}
	contentDigest := "sha256:" + hex.EncodeToString(hasher.Sum(nil))
	completeHash := headerHash + "|" + contentDigest
	if err := s.uploadOperations.MarkBlobStored(
		ctx, row.ID, row.OwnerToken, headerHash, completeHash, row.ObjectKey,
		time.Now().UTC().Add(durableUploadRetention),
	); err != nil {
		if errors.Is(err, persistence.ErrFileUploadOperationLostOwnership) {
			if cleanupErr := s.deleteLostUploadAttemptObject(ctx, row.ObjectKey); cleanupErr != nil {
				return nil, fmt.Errorf("%w (stale upload cleanup failed: %v)", err, cleanupErr)
			}
		}
		return nil, err
	}
	return s.commitDurableUploadMetadata(
		ctx, req, parentObjectAPIName, row, completeHash, contentDigest, meta.Size,
	)
}

func (s *ContractService) replayExistingDurableUploadResult(
	ctx context.Context,
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	systemFileID string,
) (*contract.FileUploadResult, bool, error) {
	existing, err := s.records.GetRaw(ctx, constants.TableFile, systemFileID)
	if err != nil {
		if isMissingFileRecord(err) {
			return nil, false, nil
		}
		return nil, false, err
	}
	if existing == nil {
		return nil, false, nil
	}
	existingObjectKey, _ := existing[constants.FieldSysFile_StorageKey].(string)
	if strings.TrimSpace(existingObjectKey) == "" {
		return nil, true, sharederrors.NewMalformedRequestError(
			"file idempotency identity has no committed storage key",
		)
	}
	contentDigest, _ := existing[constants.FieldSysFile_Checksum].(string)
	result, err := durableUploadResultFromRecord(
		existing, req, parentObjectAPIName, existingObjectKey, contentDigest,
	)
	if err != nil {
		return nil, true, err
	}
	store, err := s.storeForAuthority(
		existing[constants.FieldSysFile_StorageProvider],
		existing[constants.FieldSysFile_StorageBucket],
		existing[constants.FieldSysFile_SourceType],
		false,
	)
	if err != nil {
		return nil, true, fmt.Errorf("reconcile existing durable file authority: %w", err)
	}
	meta, storedDigest, err := inspectDurableStoredObject(ctx, store, existingObjectKey)
	if err != nil {
		return nil, true, fmt.Errorf("reconcile existing durable file object: %w", err)
	}
	if meta.Size != req.ContentLength || storedDigest != contentDigest {
		return nil, true, sharederrors.NewMalformedRequestError(
			"file idempotency identity is bound to different content",
		)
	}
	replayedDigest, err := checksumFileBody(req.Body)
	if err != nil {
		return nil, true, err
	}
	if replayedDigest != contentDigest {
		return nil, true, sharederrors.NewMalformedRequestError(
			"file idempotency identity is bound to different content",
		)
	}
	return result, true, nil
}

func (s *ContractService) reconcileDurableUpload(
	ctx context.Context,
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	row persistence.FileUploadOperation,
	headerHash string,
) (*contract.FileUploadResult, error) {
	contentDigest, ok := durableUploadContentDigest(row.RequestHash, headerHash)
	if !ok {
		return nil, fmt.Errorf("file upload journal contains an invalid request hash")
	}
	logicalObjectKey := systemFileObjectKey(
		parentObjectAPIName,
		req.ParentID,
		row.SystemFileID,
		req.FileName,
	)
	if err := validateDurableUploadAttemptIdentity(row, logicalObjectKey); err != nil {
		// The scheduled repair owner is the only path allowed to disposition a
		// malformed immutable BLOB_STORED journal. The foreground must not read
		// or commit the foreign object key.
		return nil, &uploadRepairRequiredError{}
	}
	store, err := s.storeForAuthority(
		row.StorageProvider,
		row.StorageBucket,
		"",
		false,
	)
	if err != nil {
		return nil, err
	}
	meta, storedDigest, err := inspectDurableStoredObject(ctx, store, row.ObjectKey)
	if errors.Is(err, storage.ErrObjectNotFound) {
		// BLOB_STORED is immutable in the foreground serving path. Reassigning
		// it here would create a second owner while a prior reconciler may be
		// committing _System_File metadata. The scheduled repair work family
		// owns any future fenced transition for a missing durable blob.
		return nil, &uploadRepairRequiredError{}
	}
	if err != nil {
		return nil, err
	}
	if meta.Size != req.ContentLength || storedDigest != contentDigest {
		return nil, sharederrors.NewMalformedRequestError("file idempotency identity is bound to different content")
	}
	replayedDigest, err := checksumFileBody(req.Body)
	if err != nil {
		return nil, err
	}
	if replayedDigest != contentDigest {
		return nil, sharederrors.NewMalformedRequestError("file idempotency identity is bound to different content")
	}
	return s.commitDurableUploadMetadata(
		ctx, req, parentObjectAPIName, row, row.RequestHash, contentDigest, meta.Size,
	)
}

func inspectDurableStoredObject(
	ctx context.Context,
	store storage.ObjectStore,
	objectKey string,
) (storage.ObjectMetadata, string, error) {
	reader, meta, err := store.GetObject(ctx, objectKey)
	if err != nil {
		return storage.ObjectMetadata{}, "", err
	}
	hasher := sha256.New()
	size, readErr := io.Copy(hasher, reader)
	closeErr := reader.Close()
	if readErr != nil {
		return storage.ObjectMetadata{}, "", readErr
	}
	if closeErr != nil {
		return storage.ObjectMetadata{}, "", closeErr
	}
	if size != meta.Size {
		return storage.ObjectMetadata{}, "", errors.New("file object size receipt does not match stored bytes")
	}
	return meta, "sha256:" + hex.EncodeToString(hasher.Sum(nil)), nil
}

func (s *ContractService) replayCompletedDurableUpload(
	ctx context.Context,
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	row persistence.FileUploadOperation,
	headerHash string,
) (*contract.FileUploadResult, error) {
	contentDigest, ok := durableUploadContentDigest(row.RequestHash, headerHash)
	if !ok {
		return nil, fmt.Errorf("file upload journal contains an invalid completed request hash")
	}
	replayedDigest, err := checksumFileBody(req.Body)
	if err != nil {
		return nil, err
	}
	if replayedDigest != contentDigest {
		return nil, sharederrors.NewMalformedRequestError("file idempotency identity is bound to different content")
	}
	existing, err := s.records.GetRaw(ctx, constants.TableFile, row.SystemFileID)
	if err != nil {
		return nil, err
	}
	return durableUploadResultFromJournalRecord(
		existing,
		req,
		parentObjectAPIName,
		row,
		contentDigest,
	)
}

func (s *ContractService) commitDurableUploadMetadata(
	ctx context.Context,
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	row persistence.FileUploadOperation,
	completeHash string,
	contentDigest string,
	size int64,
) (*contract.FileUploadResult, error) {
	var committed *contract.FileUploadResult
	err := s.uploadOperations.FinalizeBlobStored(
		ctx, row.ID, row.OwnerToken, completeHash, row.ObjectKey,
		time.Now().UTC().Add(durableUploadRetention),
		func(txCtx context.Context) error {
			existing, existingErr := s.records.GetRaw(txCtx, constants.TableFile, row.SystemFileID)
			if existingErr == nil && existing != nil {
				result, matchErr := durableUploadResultFromJournalRecord(
					existing, req, parentObjectAPIName, row, contentDigest,
				)
				if matchErr != nil {
					return matchErr
				}
				committed = result
				return nil
			}
			if existingErr != nil && !isMissingFileRecord(existingErr) {
				return existingErr
			}
			record := s.recordAttachmentMetadata(
				req, parentObjectAPIName, row.SystemFileID, row.ObjectKey, contentDigest, size,
			)
			record[constants.FieldSysFile_StorageProvider] = row.StorageProvider
			record[constants.FieldSysFile_StorageBucket] = row.StorageBucket
			createCtx := constants.WithSecurityContext(
				txCtx, constants.ServiceContext, fileMetadataWriteSecurityReason,
			)
			if _, insertErr := s.records.Insert(
				createCtx, constants.TableFile, record, req.User,
			); insertErr != nil {
				// The deterministic row can pre-exist after an ambiguous older
				// attempt. Accept only an exact identity inside this same locked
				// transaction.
				existing, readErr := s.records.GetRaw(txCtx, constants.TableFile, row.SystemFileID)
				if readErr != nil || existing == nil {
					return insertErr
				}
				result, matchErr := durableUploadResultFromJournalRecord(
					existing, req, parentObjectAPIName, row, contentDigest,
				)
				if matchErr != nil {
					return insertErr
				}
				committed = result
				return nil
			}
			committed = &contract.FileUploadResult{
				ID: row.SystemFileID, Name: sanitizeUploadedFileName(req.FileName),
				Size: size, Mime: req.ContentType,
			}
			return nil
		},
	)
	if err == nil {
		return committed, nil
	}
	// A commit acknowledgement can be ambiguous even though TiDB durably
	// committed both facts. Re-read the journal and immutable metadata; accept
	// only the exact completed identity.
	reloaded, loadErr := s.uploadOperations.Load(ctx, row.IdempotencyKey)
	if loadErr == nil && reloaded.State == persistence.FileUploadOperationCompleted &&
		reloaded.OwnerToken == row.OwnerToken && reloaded.RequestHash == completeHash &&
		reloaded.ObjectKey == row.ObjectKey {
		existing, readErr := s.records.GetRaw(ctx, constants.TableFile, row.SystemFileID)
		if readErr == nil && existing != nil {
			if result, matchErr := durableUploadResultFromJournalRecord(
				existing, req, parentObjectAPIName, row, contentDigest,
			); matchErr == nil {
				return result, nil
			}
		}
	}
	return nil, err
}

func (s *ContractService) markDurableUploadCompleted(
	ctx context.Context,
	row persistence.FileUploadOperation,
	completeHash string,
) error {
	err := s.uploadOperations.MarkCompleted(
		ctx, row.ID, row.OwnerToken, completeHash, row.ObjectKey,
		time.Now().UTC().Add(durableUploadRetention),
	)
	if !errors.Is(err, persistence.ErrFileUploadOperationLostOwnership) {
		return err
	}
	reloaded, loadErr := s.uploadOperations.Load(ctx, row.IdempotencyKey)
	if loadErr == nil && reloaded.State == persistence.FileUploadOperationCompleted &&
		reloaded.OwnerToken == row.OwnerToken && reloaded.RequestHash == completeHash &&
		reloaded.ObjectKey == row.ObjectKey {
		return nil
	}
	return err
}

func (s *ContractService) recordAttachmentMetadata(
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	systemFileID string,
	objectKey string,
	contentDigest string,
	size int64,
) models.SObject {
	originalFileName := sanitizeUploadedFileName(req.FileName)
	record := models.SObject{
		constants.FieldID:                          systemFileID,
		constants.FieldSysFile_ParentID:            req.ParentID,
		constants.FieldSysFile_ParentObjectAPIName: parentObjectAPIName,
		constants.FieldSysFile_Name:                originalFileName,
		constants.FieldSysFile_OriginalFileName:    originalFileName,
		constants.FieldSysFile_Extension:           strings.TrimPrefix(req.Extension, "."),
		constants.FieldSysFile_MimeType:            req.ContentType,
		constants.FieldSysFile_SizeBytes:           size,
		constants.FieldSysFile_StoragePath:         objectKey,
		constants.FieldSysFile_StorageProvider:     s.storageProvider,
		constants.FieldSysFile_StorageBucket:       s.storageBucket,
		constants.FieldSysFile_StorageKey:          objectKey,
		constants.FieldSysFile_Status:              "Active",
		constants.FieldSysFile_SourceType:          systemFileSourceTypeNative,
		constants.FieldSysFile_AttachmentKind:      defaultRecordAttachmentKind,
		constants.FieldSysFile_Checksum:            contentDigest,
	}
	if strings.TrimSpace(req.AttachmentKind) != "" {
		record[constants.FieldSysFile_AttachmentKind] = strings.TrimSpace(req.AttachmentKind)
	}
	return record
}

func durableUploadResultFromRecord(
	record models.SObject,
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	objectKey string,
	contentDigest string,
) (*contract.FileUploadResult, error) {
	if record == nil {
		return nil, fmt.Errorf("completed file upload metadata is missing")
	}
	id, _ := record[constants.FieldID].(string)
	name, _ := record[constants.FieldSysFile_OriginalFileName].(string)
	mime, _ := record[constants.FieldSysFile_MimeType].(string)
	parentID, _ := record[constants.FieldSysFile_ParentID].(string)
	parentObject, _ := record[constants.FieldSysFile_ParentObjectAPIName].(string)
	checksum, _ := record[constants.FieldSysFile_Checksum].(string)
	storagePath, _ := record[constants.FieldSysFile_StoragePath].(string)
	storageKey, _ := record[constants.FieldSysFile_StorageKey].(string)
	attachmentKind, _ := record[constants.FieldSysFile_AttachmentKind].(string)
	expectedAttachmentKind := strings.TrimSpace(req.AttachmentKind)
	if expectedAttachmentKind == "" {
		expectedAttachmentKind = defaultRecordAttachmentKind
	}
	size, sizeOK := fileSizeBytes(record[constants.FieldSysFile_SizeBytes])
	if id != strings.TrimSpace(req.ID) || name != sanitizeUploadedFileName(req.FileName) ||
		mime != req.ContentType || parentID != req.ParentID ||
		parentObject != parentObjectAPIName || !sizeOK || size != req.ContentLength ||
		storagePath != objectKey || storageKey != objectKey ||
		attachmentKind != expectedAttachmentKind || checksum != contentDigest ||
		!validSHA256Digest(contentDigest) {
		return nil, sharederrors.NewMalformedRequestError("file idempotency identity is bound to different content")
	}
	return &contract.FileUploadResult{ID: id, Name: name, Size: size, Mime: mime}, nil
}

func durableUploadResultFromJournalRecord(
	record models.SObject,
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	row persistence.FileUploadOperation,
	contentDigest string,
) (*contract.FileUploadResult, error) {
	result, err := durableUploadResultFromRecord(
		record,
		req,
		parentObjectAPIName,
		row.ObjectKey,
		contentDigest,
	)
	if err != nil {
		return nil, err
	}
	provider, providerOK := record[constants.FieldSysFile_StorageProvider].(string)
	bucket, bucketOK := record[constants.FieldSysFile_StorageBucket].(string)
	if !providerOK || !bucketOK ||
		validateDurableUploadStorageAuthority(provider, bucket) != nil ||
		validateDurableUploadStorageAuthority(row.StorageProvider, row.StorageBucket) != nil ||
		!strings.EqualFold(
			strings.TrimSpace(provider),
			strings.TrimSpace(row.StorageProvider),
		) ||
		strings.TrimSpace(bucket) != strings.TrimSpace(row.StorageBucket) {
		return nil, sharederrors.NewMalformedRequestError(
			"file idempotency identity is bound to different storage authority",
		)
	}
	return result, nil
}

func durableUploadHeaderHash(
	req contract.FileUploadRequest,
	parentObjectAPIName string,
	objectKey string,
) (string, error) {
	payload, err := json.Marshal(struct {
		Domain              string `json:"domain"`
		ID                  string `json:"id"`
		FileName            string `json:"fileName"`
		ContentType         string `json:"contentType"`
		ContentLength       int64  `json:"contentLength"`
		ParentID            string `json:"parentId"`
		ParentObjectAPIName string `json:"parentObjectApiName"`
		AttachmentKind      string `json:"attachmentKind"`
		ObjectKey           string `json:"objectKey"`
	}{
		Domain: "nexuscrm.files.record-upload.v1", ID: strings.TrimSpace(req.ID),
		FileName: sanitizeUploadedFileName(req.FileName), ContentType: req.ContentType,
		ContentLength: req.ContentLength, ParentID: req.ParentID,
		ParentObjectAPIName: parentObjectAPIName,
		AttachmentKind:      strings.TrimSpace(req.AttachmentKind), ObjectKey: objectKey,
	})
	if err != nil {
		return "", err
	}
	sum := sha256.Sum256(payload)
	return "sha256:" + hex.EncodeToString(sum[:]), nil
}

func durableUploadContentDigest(completeHash, headerHash string) (string, bool) {
	prefix := headerHash + "|"
	if !strings.HasPrefix(completeHash, prefix) {
		return "", false
	}
	contentDigest := strings.TrimPrefix(completeHash, prefix)
	return contentDigest, validSHA256Digest(contentDigest)
}

func validSHA256Digest(digest string) bool {
	if !strings.HasPrefix(digest, "sha256:") {
		return false
	}
	decoded, err := hex.DecodeString(strings.TrimPrefix(digest, "sha256:"))
	return err == nil && len(decoded) == sha256.Size
}

func durableUploadLeaseUntil(ctx context.Context, now time.Time) time.Time {
	if deadline, ok := ctx.Deadline(); ok && deadline.After(now) {
		return deadline.Add(durableUploadShutdownGrace)
	}
	return now.Add(15*time.Minute + durableUploadShutdownGrace)
}

func durableUploadAttemptContext(
	ctx context.Context,
	leaseUntil time.Time,
) (context.Context, context.CancelFunc) {
	if ctx == nil {
		ctx = context.Background()
	}
	return context.WithDeadline(ctx, leaseUntil.Add(-durableUploadShutdownGrace))
}

func newDurableUploadOwnerToken() (string, error) {
	var value [16]byte
	if _, err := rand.Read(value[:]); err != nil {
		return "", fmt.Errorf("mint durable upload owner token: %w", err)
	}
	return hex.EncodeToString(value[:]), nil
}

func durableUploadAttemptObjectKey(logicalObjectKey, ownerToken string) string {
	return path.Join(path.Dir(logicalObjectKey), ".attempts", ownerToken, path.Base(logicalObjectKey))
}

func validateDurableUploadAttemptIdentity(
	operation persistence.FileUploadOperation,
	logicalObjectKey string,
) error {
	for _, component := range []string{
		operation.ParentObjectAPIName,
		operation.ParentID,
		operation.SystemFileID,
		operation.OwnerToken,
		path.Base(logicalObjectKey),
	} {
		if !validDurableUploadObjectKeySegment(component) {
			return errors.New("file upload journal attempt object identity is invalid")
		}
	}
	expectedLogicalObjectKey := path.Join(
		"system-file",
		operation.ParentObjectAPIName,
		operation.ParentID,
		operation.SystemFileID,
		path.Base(logicalObjectKey),
	)
	if logicalObjectKey != expectedLogicalObjectKey ||
		operation.ObjectKey != durableUploadAttemptObjectKey(
			expectedLogicalObjectKey,
			operation.OwnerToken,
		) {
		return errors.New("file upload journal attempt object identity is invalid")
	}
	return nil
}

func validDurableUploadObjectKeySegment(value string) bool {
	canonical := strings.TrimSpace(value)
	return value == canonical && canonical != "" &&
		canonical != "." && canonical != ".." &&
		path.Base(canonical) == canonical
}

func (s *ContractService) deleteLostUploadAttemptObject(ctx context.Context, objectKey string) error {
	if s == nil || s.store == nil || strings.TrimSpace(objectKey) == "" {
		return nil
	}
	if ctx == nil {
		ctx = context.Background()
	}
	cleanupCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
	defer cancel()
	err := s.store.DeleteObject(cleanupCtx, objectKey)
	if errors.Is(err, storage.ErrObjectNotFound) {
		return nil
	}
	return err
}

func checksumFileBody(body io.Reader) (string, error) {
	if body == nil {
		return "", sharederrors.NewMalformedRequestError("missing file body")
	}
	hasher := sha256.New()
	if _, err := io.Copy(hasher, body); err != nil {
		return "", err
	}
	return "sha256:" + hex.EncodeToString(hasher.Sum(nil)), nil
}

func fileSizeBytes(value any) (int64, bool) {
	switch typed := value.(type) {
	case int64:
		return typed, true
	case int:
		return int64(typed), true
	case uint64:
		if typed <= uint64(^uint64(0)>>1) {
			return int64(typed), true
		}
	case float64:
		if typed >= 0 && typed == float64(int64(typed)) {
			return int64(typed), true
		}
	}
	return 0, false
}

func isMissingFileRecord(err error) bool {
	if err == nil {
		return false
	}
	var statuser interface{ HTTPStatus() int }
	return errors.As(err, &statuser) && statuser.HTTPStatus() == http.StatusNotFound
}

func (s *ContractService) OpenDetachedFile(ctx context.Context, ref contract.FileBlobReference, user *models.UserSession) (*contract.FileDownload, error) {
	if err := s.authorizeFileRead(ctx, user); err != nil {
		return nil, err
	}
	reader, meta, err := s.openDetachedBlob(ctx, ref)
	if err != nil {
		return nil, s.mapStorageReadError(err)
	}
	return &contract.FileDownload{
		Reader:      reader,
		FileName:    detachedBlobFileName(ref),
		Size:        meta.Size,
		ContentType: meta.ContentType,
	}, nil
}

func (s *ContractService) OpenRecordAttachment(ctx context.Context, fileID string, user *models.UserSession) (*contract.FileDownload, bool, error) {
	download, handled, err := s.openSystemFileForDownload(ctx, fileID, user)
	if !handled {
		return nil, false, nil
	}
	return download, true, err
}

func (s *recordAttachmentMetadataAuthorizer) AuthorizeRecordAttachmentMetadata(ctx context.Context, fileID string, user *models.UserSession) (*contract.RecordAttachmentMetadata, bool, error) {
	record, handled, err := s.authorizedSystemFileRecord(ctx, fileID, user)
	if err != nil {
		return nil, handled, err
	}
	if !handled || record == nil {
		return nil, handled, nil
	}
	fileID = strings.TrimSpace(fileID)
	size, sizeOK := fileSizeBytes(record[constants.FieldSysFile_SizeBytes])
	contentType, _ := record[constants.FieldSysFile_MimeType].(string)
	checksum, _ := record[constants.FieldSysFile_Checksum].(string)
	if !sizeOK || size < 0 || strings.TrimSpace(contentType) == "" || !validSHA256Digest(checksum) {
		return nil, true, errors.New("file metadata integrity is incomplete")
	}
	return &contract.RecordAttachmentMetadata{
		FileID: fileID, FileName: resolveSystemFileName(record, fileID),
		ContentType: strings.TrimSpace(contentType), ContentLength: uint64(size),
		ContentDigest: checksum,
	}, true, nil
}

// authorizeRecordAttachmentIdentity returns only the stable facts required by
// compatibility source resolution. Delivery metadata is deliberately excluded:
// legacy _System_File rows may predate mandatory MIME and checksum publication,
// while new outbound-mail delivery must continue to require both.
func (s *recordAttachmentMetadataAuthorizer) authorizeRecordAttachmentIdentity(ctx context.Context, fileID string, user *models.UserSession) (*contract.RecordAttachmentSourceResult, bool, error) {
	record, handled, err := s.authorizedSystemFileRecord(ctx, fileID, user)
	if err != nil {
		return nil, handled, err
	}
	if !handled || record == nil {
		return nil, handled, nil
	}
	fileID = strings.TrimSpace(fileID)
	return &contract.RecordAttachmentSourceResult{
		FileID: fileID, FileName: resolveSystemFileName(record, fileID),
	}, true, nil
}

func (s *recordAttachmentMetadataAuthorizer) ResolveAuthorizedRecordAttachmentSource(ctx context.Context, req contract.RecordAttachmentSourceRequest, lookup contract.RecordAttachmentSourceLookup, user *models.UserSession) (*contract.RecordAttachmentSourceResult, bool, error) {
	if s == nil || s.records == nil || s.permissions == nil || lookup == nil {
		return nil, false, nil
	}
	parentID := strings.TrimSpace(req.ParentID)
	if parentID == "" || user == nil {
		return nil, false, nil
	}
	if err := s.authorizeParentAccess(ctx, req.ParentObjectAPIName, parentID, user); err != nil {
		return nil, true, err
	}

	lookupResult, found, err := lookup.LookupRecordAttachmentSource(ctx, req)
	if err != nil {
		return nil, true, err
	}
	if !found || lookupResult == nil || strings.TrimSpace(lookupResult.FileID) == "" {
		return nil, found, nil
	}

	identity, found, err := s.authorizeRecordAttachmentIdentity(ctx, lookupResult.FileID, user)
	if err != nil {
		return nil, true, nil
	}
	if !found || identity == nil {
		return nil, true, nil
	}
	fileID := strings.TrimSpace(identity.FileID)
	if fileID == "" {
		fileID = strings.TrimSpace(lookupResult.FileID)
	}
	fileName := strings.TrimSpace(identity.FileName)
	if fileName == "" {
		fileName = fileID
	}
	return &contract.RecordAttachmentSourceResult{FileID: fileID, FileName: fileName}, true, nil
}

func (s *ContractService) DeleteRecordAttachment(ctx context.Context, fileID string, user *models.UserSession) error {
	if s.records == nil || s.permissions == nil {
		return fmt.Errorf("file delete service unavailable")
	}
	if err := s.permissions.CheckPermissionOrErrorWithUser(ctx, constants.TableFile, constants.PermDelete, user); err != nil {
		return err
	}

	record, err := s.records.GetRaw(ctx, constants.TableFile, fileID)
	if err != nil {
		return err
	}
	if record == nil {
		return nil
	}

	parentID, _ := record[constants.FieldSysFile_ParentID].(string)
	parentObjectAPIName, _ := record[constants.FieldSysFile_ParentObjectAPIName].(string)
	if err := s.authorizeParentAccess(ctx, parentObjectAPIName, parentID, user); err != nil {
		return err
	}

	if status, _ := record[constants.FieldSysFile_Status].(string); strings.EqualFold(status, "Deleted") {
		if hasPendingStoredObject(record) {
			return s.deleteStoredObjectForRecord(ctx, record)
		}
		return nil
	}

	if sourceType, _ := record[constants.FieldSysFile_SourceType].(string); isCompatSystemFileSourceType(sourceType) {
		return sharederrors.NewMalformedRequestError("compatibility files cannot be deleted")
	}

	deleteCtx := constants.WithSecurityContext(ctx, constants.SystemContext, fileMetadataDeleteSecurityReason)
	if err := s.softDeleteRecordAttachment(deleteCtx, fileID, user); err != nil {
		return err
	}
	return s.deleteStoredObjectForRecord(ctx, record)
}

const (
	defaultRecordAttachmentKind       = "record"
	fileMetadataWriteSecurityReason   = "file upload metadata write"
	fileMetadataDeleteSecurityReason  = "file delete metadata cleanup"
	systemFileSourceTypeNative        = "native"
	systemFileSourceTypeContentCompat = "content_compat"
	systemFileSourceTypeHrefCompat    = "href_compat"
	systemFileUnknownParentObject     = "Unknown"
)

func systemFileObjectKey(parentObjectAPIName, parentID, systemFileID, originalFileName string) string {
	return path.Join(
		"system-file",
		parentObjectAPIName,
		parentID,
		systemFileID,
		sanitizeUploadedFileName(originalFileName),
	)
}

func sanitizeUploadedFileName(filename string) string {
	name := strings.TrimSpace(filepath.Base(filename))
	if name == "." || name == "/" || name == "" {
		return "file"
	}
	return name
}

// OpenFrozenRecordAttachment opens only a record whose current immutable
// metadata exactly matches the reference previously authorized and frozen by
// Runtime. It is intentionally not part of the dialect Files interface.
func (s *ContractService) OpenFrozenRecordAttachment(ctx context.Context, expected contract.RecordAttachmentMetadata) (*contract.FileDownload, error) {
	if s == nil || s.records == nil || strings.TrimSpace(expected.FileID) == "" {
		return nil, errors.New("frozen file read is unavailable")
	}
	record, err := s.records.GetRaw(ctx, constants.TableFile, strings.TrimSpace(expected.FileID))
	if err != nil || record == nil {
		return nil, sharederrors.NewNotFoundWireError("File not found")
	}
	status, _ := record[constants.FieldSysFile_Status].(string)
	size, sizeOK := fileSizeBytes(record[constants.FieldSysFile_SizeBytes])
	contentType, _ := record[constants.FieldSysFile_MimeType].(string)
	checksum, _ := record[constants.FieldSysFile_Checksum].(string)
	if strings.EqualFold(status, "Deleted") || !sizeOK || size < 0 ||
		resolveSystemFileName(record, expected.FileID) != expected.FileName ||
		strings.TrimSpace(contentType) != expected.ContentType || uint64(size) != expected.ContentLength ||
		checksum != expected.ContentDigest {
		return nil, errors.New("frozen file metadata no longer matches")
	}
	download, err := s.openSystemFileRecord(ctx, record, expected.FileID)
	if err != nil {
		return nil, err
	}
	// Storage metadata is an observation of the backing object. Filesystem
	// stores re-sniff on read and may add parameters such as charset, while the
	// already-verified _System_File value is the immutable delivery authority.
	download.ContentType = expected.ContentType
	return download, nil
}

func (s *ContractService) openSystemFileForDownload(ctx context.Context, fileID string, user *models.UserSession) (*contract.FileDownload, bool, error) {
	record, handled, err := s.authorizedSystemFileRecord(ctx, fileID, user)
	if !handled || err != nil {
		return nil, handled, err
	}
	download, err := s.openSystemFileRecord(ctx, record, fileID)
	return download, true, err
}

func (s *ContractService) openSystemFileRecord(ctx context.Context, record models.SObject, fileID string) (*contract.FileDownload, error) {
	var reader io.ReadCloser
	var meta storage.ObjectMetadata
	var err error
	if storageKey, _ := record[constants.FieldSysFile_StorageKey].(string); strings.TrimSpace(storageKey) != "" {
		reader, meta, err = s.openStoredObject(ctx, record, storageKey)
		if err != nil {
			return nil, s.mapStorageReadError(err)
		}
		return s.downloadFromStorage(reader, meta, resolveSystemFileName(record, fileID)), nil
	}

	if storagePath, _ := record[constants.FieldSysFile_StoragePath].(string); strings.TrimSpace(storagePath) != "" {
		if bucket, key, ok := parseS3ObjectReference(storagePath); ok {
			shadowRecord := cloneFileRecord(record)
			shadowRecord[constants.FieldSysFile_StorageProvider] = storage.ProviderS3
			shadowRecord[constants.FieldSysFile_StorageBucket] = bucket
			reader, meta, err = s.openStoredObject(ctx, shadowRecord, key)
			if err != nil {
				return nil, s.mapStorageReadError(err)
			}
			return s.downloadFromStorage(reader, meta, resolveSystemFileName(record, fileID)), nil
		}
		sourceType, _ := record[constants.FieldSysFile_SourceType].(string)
		ref := s.resolveDetachedReference(sourceType, storagePath)
		reader, meta, err = s.openDetachedBlob(ctx, ref)
		if err != nil {
			return nil, s.mapStorageReadError(err)
		}
		return s.downloadFromStorage(reader, meta, resolveSystemFileName(record, detachedBlobFileName(ref))), nil
	}

	return nil, sharederrors.NewNotFoundWireError("File not found")
}

func (s *recordAttachmentMetadataAuthorizer) authorizedSystemFileRecord(ctx context.Context, fileID string, user *models.UserSession) (models.SObject, bool, error) {
	if s.records == nil || s.permissions == nil {
		return nil, false, nil
	}

	record, err := s.records.GetRaw(ctx, constants.TableFile, fileID)
	if err != nil {
		return nil, true, err
	}
	if record == nil {
		return nil, false, nil
	}

	status, _ := record[constants.FieldSysFile_Status].(string)
	if strings.EqualFold(status, "Deleted") {
		return nil, true, sharederrors.NewNotFoundWireError("File not found")
	}

	if err := s.permissions.CheckPermissionOrErrorWithUser(ctx, constants.TableFile, constants.PermRead, user); err != nil {
		return nil, true, err
	}
	parentID, _ := record[constants.FieldSysFile_ParentID].(string)
	parentObjectAPIName, _ := record[constants.FieldSysFile_ParentObjectAPIName].(string)
	if err := s.authorizeParentAccess(ctx, parentObjectAPIName, parentID, user); err != nil {
		return nil, true, err
	}

	return record, true, nil
}

func (s *ContractService) downloadFromStorage(reader io.ReadCloser, meta storage.ObjectMetadata, fileName string) *contract.FileDownload {
	return &contract.FileDownload{
		Reader:      reader,
		FileName:    fileName,
		Size:        meta.Size,
		ContentType: meta.ContentType,
	}
}

func (s *ContractService) openStoredObject(ctx context.Context, record models.SObject, objectKey string) (io.ReadCloser, storage.ObjectMetadata, error) {
	store, err := s.storeForAuthority(
		record[constants.FieldSysFile_StorageProvider],
		record[constants.FieldSysFile_StorageBucket],
		record[constants.FieldSysFile_SourceType],
		true,
	)
	if err != nil {
		return nil, storage.ObjectMetadata{}, err
	}
	return store.GetObject(ctx, objectKey)
}

func (s *ContractService) storeForAuthority(
	providerValue interface{},
	bucketValue interface{},
	sourceTypeValue interface{},
	allowCurrentDefault bool,
) (storage.ObjectStore, error) {
	provider, _ := providerValue.(string)
	provider = strings.ToLower(strings.TrimSpace(provider))
	bucket, _ := bucketValue.(string)
	bucket = strings.TrimSpace(bucket)
	sourceType, _ := sourceTypeValue.(string)
	sourceType = strings.ToLower(strings.TrimSpace(sourceType))
	if allowCurrentDefault {
		if provider == "" {
			provider = strings.ToLower(strings.TrimSpace(s.storageProvider))
		}
		if bucket == "" {
			bucket = strings.TrimSpace(s.storageBucket)
		}
	}
	if provider == "" || bucket == "" {
		return nil, errors.New("file storage authority is incomplete")
	}
	if s.storageAuthorities != nil {
		if authority, ok := s.storageAuthorities.Resolve(provider, bucket, sourceType); ok {
			if authority.Primary {
				return s.store, nil
			}
			return s.resolveStore(authority.Config)
		}
		if s.storageAuthorities.Governs(provider, bucket) {
			return nil, errors.New("file storage authority is not admitted for the record source type")
		}
	}
	if provider == strings.ToLower(strings.TrimSpace(s.storageProvider)) &&
		bucket == strings.TrimSpace(s.storageBucket) {
		return s.store, nil
	}
	cfg := storage.LoadConfigFromEnv()
	cfg.Provider = provider
	cfg.Bucket = bucket
	return s.resolveStore(cfg)
}

func (s *ContractService) openDetachedBlob(ctx context.Context, ref contract.FileBlobReference) (io.ReadCloser, storage.ObjectMetadata, error) {
	objectKey := strings.TrimSpace(ref.StorageKey)
	if objectKey == "" {
		return nil, storage.ObjectMetadata{}, storage.ErrObjectNotFound
	}
	reader, meta, err := s.store.GetObject(ctx, objectKey)
	if err == nil {
		return reader, meta, nil
	}
	if !errors.Is(err, storage.ErrObjectNotFound) {
		return nil, storage.ObjectMetadata{}, err
	}
	if !s.allowLegacyFileFallback {
		return nil, storage.ObjectMetadata{}, storage.ErrObjectNotFound
	}
	return s.openDetachedLegacyFile(ref.LegacyFileName)
}

func (s *ContractService) openDetachedLegacyFile(fileName string) (io.ReadCloser, storage.ObjectMetadata, error) {
	fileName = strings.TrimSpace(fileName)
	if fileName == "" {
		return nil, storage.ObjectMetadata{}, storage.ErrObjectNotFound
	}
	fullPath := filepath.Join(s.legacyUploadRoot, filepath.Base(fileName))
	file, err := os.Open(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, storage.ObjectMetadata{}, storage.ErrObjectNotFound
		}
		return nil, storage.ObjectMetadata{}, fmt.Errorf("open legacy upload: %w", err)
	}

	info, err := file.Stat()
	if err != nil {
		_ = file.Close()
		return nil, storage.ObjectMetadata{}, fmt.Errorf("stat legacy upload: %w", err)
	}

	contentType, err := sniffOpenFileContentType(file)
	if err != nil {
		_ = file.Close()
		return nil, storage.ObjectMetadata{}, err
	}

	return file, storage.ObjectMetadata{
		Key:          fullPath,
		Size:         info.Size(),
		ContentType:  contentType,
		LastModified: info.ModTime(),
	}, nil
}

func (s *ContractService) resolveDetachedReference(sourceType string, reference string) contract.FileBlobReference {
	reference = strings.TrimSpace(reference)
	if s.detachedReferenceResolvers != nil {
		if resolver := s.detachedReferenceResolvers[normalizeDetachedReferenceSourceType(sourceType)]; resolver != nil {
			if ref, ok := resolver(reference); ok {
				return ref
			}
		}
	}
	return contract.FileBlobReference{
		StorageKey:     reference,
		LegacyFileName: filepath.Base(reference),
		FileName:       filepath.Base(reference),
	}
}

func normalizeDetachedReferenceSourceType(sourceType string) string {
	return strings.ToLower(strings.TrimSpace(sourceType))
}

func sniffOpenFileContentType(file *os.File) (string, error) {
	sniffBuf := make([]byte, 512)
	n, err := file.Read(sniffBuf)
	if err != nil && err != io.EOF {
		return "", fmt.Errorf("sniff content type: %w", err)
	}
	if _, err := file.Seek(0, io.SeekStart); err != nil {
		return "", fmt.Errorf("rewind after sniffing: %w", err)
	}
	if n == 0 {
		return "application/octet-stream", nil
	}
	return http.DetectContentType(sniffBuf[:n]), nil
}

func parseS3ObjectReference(fileRef string) (bucket string, key string, ok bool) {
	parsed, err := url.Parse(strings.TrimSpace(fileRef))
	if err != nil || !strings.EqualFold(parsed.Scheme, "s3") {
		return "", "", false
	}
	bucket = strings.TrimSpace(parsed.Host)
	key = strings.TrimPrefix(strings.TrimSpace(parsed.Path), "/")
	if bucket == "" || key == "" {
		return "", "", false
	}
	return bucket, key, true
}

func resolveSystemFileName(record models.SObject, fallback string) string {
	for _, key := range []string{constants.FieldSysFile_OriginalFileName, constants.FieldSysFile_Name} {
		if value, ok := record[key].(string); ok && strings.TrimSpace(value) != "" {
			return value
		}
	}
	return fallback
}

func detachedBlobFileName(ref contract.FileBlobReference) string {
	for _, candidate := range []string{ref.FileName, ref.LegacyFileName, filepath.Base(ref.StorageKey)} {
		candidate = strings.TrimSpace(candidate)
		if candidate != "" && candidate != "." && candidate != "/" {
			return candidate
		}
	}
	return "file"
}

func cloneFileRecord(src models.SObject) models.SObject {
	if src == nil {
		return nil
	}
	dst := make(models.SObject, len(src))
	for key, value := range src {
		dst[key] = value
	}
	return dst
}

func (s *ContractService) authorizeFileCreate(ctx context.Context, user *models.UserSession) error {
	if s.permissions == nil {
		return nil
	}
	return s.permissions.CheckPermissionOrErrorWithUser(ctx, constants.TableFile, constants.PermCreate, user)
}

func (s *ContractService) authorizeFileRead(ctx context.Context, user *models.UserSession) error {
	if s.permissions == nil {
		return nil
	}
	return s.permissions.CheckPermissionOrErrorWithUser(ctx, constants.TableFile, constants.PermRead, user)
}

func (s *recordAttachmentMetadataAuthorizer) authorizeParentAccess(ctx context.Context, parentObjectAPIName, parentID string, user *models.UserSession) error {
	if s.records == nil {
		return fmt.Errorf("file parent authorization requires persistence")
	}
	parentID = strings.TrimSpace(parentID)
	if parentID == "" {
		return sharederrors.NewMalformedRequestError("missing file parent context")
	}

	resolvedParentObjectAPIName, err := s.resolveParentObjectAPIName(ctx, parentObjectAPIName, parentID)
	if err != nil {
		return err
	}

	if strings.EqualFold(resolvedParentObjectAPIName, constants.TableComment) {
		return s.authorizeCommentParentAccess(ctx, parentID, user)
	}

	_, err = s.records.Retrieve(ctx, resolvedParentObjectAPIName, parentID, user)
	return err
}

func (s *recordAttachmentMetadataAuthorizer) resolveParentObjectAPIName(ctx context.Context, parentObjectAPIName, parentID string) (string, error) {
	parentObjectAPIName = strings.TrimSpace(parentObjectAPIName)
	if parentObjectAPIName != "" && !strings.EqualFold(parentObjectAPIName, systemFileUnknownParentObject) {
		return parentObjectAPIName, nil
	}

	comment, err := s.records.GetRaw(ctx, constants.TableComment, parentID)
	if err != nil {
		return "", err
	}
	if comment != nil {
		return constants.TableComment, nil
	}

	if s.metadata != nil {
		if inferredParentObjectAPIName, ok := s.metadata.ResolveObjectForRecordID(ctx, parentID); ok {
			return inferredParentObjectAPIName, nil
		}
	}

	return "", sharederrors.NewMalformedRequestError("missing file parent context")
}

func (s *recordAttachmentMetadataAuthorizer) authorizeCommentParentAccess(ctx context.Context, commentID string, user *models.UserSession) error {
	comment, err := s.records.GetRaw(ctx, constants.TableComment, commentID)
	if err != nil {
		return err
	}
	if comment == nil {
		return sharederrors.NewNotFoundWireError("Comment not found")
	}

	commentObjectAPIName, _ := comment[constants.FieldSysComment_ObjectAPIName].(string)
	commentRecordID, _ := comment[constants.FieldSysComment_RecordID].(string)
	if commentObjectAPIName == "" || commentRecordID == "" {
		return sharederrors.NewMalformedRequestError("comment is missing parent record context")
	}

	_, err = s.records.Retrieve(ctx, commentObjectAPIName, commentRecordID, user)
	return err
}

func (s *ContractService) softDeleteRecordAttachment(ctx context.Context, fileID string, user *models.UserSession) error {
	updates := models.SObject{
		constants.FieldSysFile_Status:      "Deleted",
		constants.FieldSysFile_DeletedDate: utils.NowTimestamp(),
		constants.FieldSysFile_DeletedByID: constants.SystemUserID,
	}
	if user != nil && strings.TrimSpace(user.ID) != "" {
		updates[constants.FieldSysFile_DeletedByID] = user.ID
	}
	return s.records.Update(ctx, constants.TableFile, fileID, updates, user)
}

func hasPendingStoredObject(record models.SObject) bool {
	if record == nil {
		return false
	}
	if sourceType, _ := record[constants.FieldSysFile_SourceType].(string); isCompatSystemFileSourceType(sourceType) {
		return false
	}
	if storageKey, _ := record[constants.FieldSysFile_StorageKey].(string); strings.TrimSpace(storageKey) != "" {
		return true
	}
	if storagePath, _ := record[constants.FieldSysFile_StoragePath].(string); strings.TrimSpace(storagePath) != "" {
		return true
	}
	return false
}

func (s *ContractService) deleteStoredObjectForRecord(ctx context.Context, record models.SObject) error {
	if sourceType, _ := record[constants.FieldSysFile_SourceType].(string); isCompatSystemFileSourceType(sourceType) {
		return sharederrors.NewMalformedRequestError("compatibility files cannot be deleted")
	}

	if storageKey, _ := record[constants.FieldSysFile_StorageKey].(string); strings.TrimSpace(storageKey) != "" {
		return s.cleanupStoredObject(ctx, record, storageKey)
	}

	if storagePath, _ := record[constants.FieldSysFile_StoragePath].(string); strings.TrimSpace(storagePath) != "" {
		if bucket, key, ok := parseS3ObjectReference(storagePath); ok {
			shadowRecord := cloneFileRecord(record)
			shadowRecord[constants.FieldSysFile_StorageProvider] = storage.ProviderS3
			shadowRecord[constants.FieldSysFile_StorageBucket] = bucket
			return s.cleanupStoredObject(ctx, shadowRecord, key)
		}
		sourceType, _ := record[constants.FieldSysFile_SourceType].(string)
		return s.cleanupDetachedObject(ctx, s.resolveDetachedReference(sourceType, storagePath))
	}
	return nil
}

func isCompatSystemFileSourceType(sourceType string) bool {
	switch strings.ToLower(strings.TrimSpace(sourceType)) {
	case systemFileSourceTypeContentCompat, systemFileSourceTypeHrefCompat:
		return true
	default:
		return false
	}
}

func (s *ContractService) cleanupStoredObject(ctx context.Context, record models.SObject, objectKey string) error {
	storeToUse, err := s.storeForAuthority(
		record[constants.FieldSysFile_StorageProvider],
		record[constants.FieldSysFile_StorageBucket],
		record[constants.FieldSysFile_SourceType],
		true,
	)
	if err != nil {
		return err
	}

	err = storeToUse.DeleteObject(ctx, objectKey)
	if err == nil || errors.Is(err, storage.ErrObjectNotFound) {
		return nil
	}
	return err
}

func (s *ContractService) cleanupDetachedObject(ctx context.Context, ref contract.FileBlobReference) error {
	var firstErr error
	if objectKey := strings.TrimSpace(ref.StorageKey); objectKey != "" {
		if err := s.store.DeleteObject(ctx, objectKey); err != nil && !errors.Is(err, storage.ErrObjectNotFound) {
			firstErr = err
		}
	}

	if legacyFileName := strings.TrimSpace(ref.LegacyFileName); s.allowLegacyFileFallback && legacyFileName != "" {
		fullPath := filepath.Join(s.legacyUploadRoot, filepath.Base(legacyFileName))
		if err := os.Remove(fullPath); err != nil && !os.IsNotExist(err) && firstErr == nil {
			firstErr = err
		}
	}

	return firstErr
}

func (s *ContractService) mapStorageReadError(err error) error {
	if errors.Is(err, storage.ErrObjectNotFound) {
		return sharederrors.NewNotFoundWireError("File not found")
	}
	return err
}
