package attachment

import (
	"context"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
)

func (store *Store) UploadAttachmentsForUser(ctx context.Context, userID string, workspaceID string, scopeID string, attachments []CreateAttachmentParams) ([]AppAttachment, error) {
	var result []AppAttachment
	var txs TxStore
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		txs = store.InTx(tx)
		var err error
		result, err = store.InTx(tx).UploadAttachmentsForUser(ctx, userID, workspaceID, scopeID, attachments)
		return err
	})
	if err != nil {
		txs.cleanupUploadedMediaObjects(ctx)
		txs.releaseUploadedMediaObjectTracker()
		return nil, err
	}
	txs.releaseUploadedMediaObjectTracker()
	return result, nil
}

func (store *Store) UploadAttachmentsForMember(ctx context.Context, memberID string, workspaceID string, scopeID string, attachments []CreateAttachmentParams) ([]AppAttachment, error) {
	var result []AppAttachment
	var txs TxStore
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		txs = store.InTx(tx)
		var err error
		result, err = store.InTx(tx).UploadAttachmentsForMember(ctx, memberID, workspaceID, scopeID, attachments)
		return err
	})
	if err != nil {
		txs.cleanupUploadedMediaObjects(ctx)
		txs.releaseUploadedMediaObjectTracker()
		return nil, err
	}
	txs.releaseUploadedMediaObjectTracker()
	return result, nil
}

func (store *Store) LoadAttachmentForUser(ctx context.Context, userID string, workspaceID string, attachmentID string) (AttachmentDownload, error) {
	var result AttachmentDownload
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).LoadAttachmentForUser(ctx, userID, workspaceID, attachmentID)
		return err
	})
	if err != nil {
		return AttachmentDownload{}, err
	}
	return result, nil
}

func (store *Store) LoadAttachmentForMember(ctx context.Context, memberID string, workspaceID string, attachmentID string) (AttachmentDownload, error) {
	var result AttachmentDownload
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).LoadAttachmentForMember(ctx, memberID, workspaceID, attachmentID)
		return err
	})
	if err != nil {
		return AttachmentDownload{}, err
	}
	return result, nil
}

// AuthorizeAttachmentRead checks read permission without loading the blob.
// Used by the thumbnail endpoint before checking the cache so cache hits don't
// trigger an OSS original fetch.
func (store *Store) AuthorizeAttachmentRead(ctx context.Context, workspaceID string, attachmentID string, userID string, isAgentToken bool, agentMemberID string) error {
	return coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		return store.InTx(tx).authorizeAttachmentRead(ctx, workspaceID, attachmentID, userID, isAgentToken, agentMemberID)
	})
}

func (store *Store) UploadUserAvatar(ctx context.Context, userID string, workspaceID string, params CreateAttachmentParams) (string, error) {
	var result string
	var txs TxStore
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		txs = store.InTx(tx)
		var err error
		result, err = store.InTx(tx).UploadUserAvatar(ctx, userID, workspaceID, params)
		return err
	})
	if err != nil {
		txs.cleanupUploadedMediaObjects(ctx)
		txs.releaseUploadedMediaObjectTracker()
		return "", err
	}
	txs.releaseUploadedMediaObjectTracker()
	return result, nil
}

func (store *Store) UploadAgentAvatar(ctx context.Context, workspaceID string, agentID string, params CreateAttachmentParams) (string, error) {
	var result string
	var txs TxStore
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		txs = store.InTx(tx)
		var err error
		result, err = store.InTx(tx).UploadAgentAvatar(ctx, workspaceID, agentID, params)
		return err
	})
	if err != nil {
		txs.cleanupUploadedMediaObjects(ctx)
		txs.releaseUploadedMediaObjectTracker()
		return "", err
	}
	txs.releaseUploadedMediaObjectTracker()
	return result, nil
}

func (store *Store) UploadResourceAvatar(ctx context.Context, workspaceID string, ownerKind string, ownerID string, params CreateAttachmentParams) (string, error) {
	var result string
	var txs TxStore
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		txs = store.InTx(tx)
		var err error
		result, err = txs.UploadResourceAvatar(ctx, workspaceID, ownerKind, ownerID, params)
		return err
	})
	if err != nil {
		txs.cleanupUploadedMediaObjects(ctx)
		txs.releaseUploadedMediaObjectTracker()
		return "", err
	}
	txs.releaseUploadedMediaObjectTracker()
	return result, nil
}

func (store *Store) LoadAvatar(ctx context.Context, avatarID string) (AttachmentDownload, error) {
	var result AttachmentDownload
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).LoadAvatar(ctx, avatarID)
		return err
	})
	if err != nil {
		return AttachmentDownload{}, err
	}
	return result, nil
}

func (store *Store) LoadUserAvatar(ctx context.Context, userID string) (AttachmentDownload, error) {
	var result AttachmentDownload
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).LoadUserAvatar(ctx, userID)
		return err
	})
	if err != nil {
		return AttachmentDownload{}, err
	}
	return result, nil
}

func (store *Store) LoadAgentAvatar(ctx context.Context, workspaceID string, agentID string) (AttachmentDownload, error) {
	var result AttachmentDownload
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).LoadAgentAvatar(ctx, workspaceID, agentID)
		return err
	})
	if err != nil {
		return AttachmentDownload{}, err
	}
	return result, nil
}

func (store *Store) ResolveUserAvatarRef(ctx context.Context, userID string) (AvatarVariantRef, error) {
	var result AvatarVariantRef
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).ResolveUserAvatarRef(ctx, userID)
		return err
	})
	if err != nil {
		return AvatarVariantRef{}, err
	}
	return result, nil
}

func (store *Store) ResolveAgentAvatarRef(ctx context.Context, workspaceID string, agentID string) (AvatarVariantRef, error) {
	var result AvatarVariantRef
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).ResolveAgentAvatarRef(ctx, workspaceID, agentID)
		return err
	})
	if err != nil {
		return AvatarVariantRef{}, err
	}
	return result, nil
}

func (store *Store) ClaimAttachmentsForMessage(ctx context.Context, workspaceID string, scopeID string, uploadedByMemberID string, messageID string, attachmentIDs []string) ([]AppAttachment, error) {
	var result []AppAttachment
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).ClaimAttachmentsForMessage(ctx, workspaceID, scopeID, uploadedByMemberID, messageID, attachmentIDs)
		return err
	})
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (store *Store) LoadAttachmentsForMessages(ctx context.Context, workspaceID string, messageIDs []string) (map[string][]AppAttachment, error) {
	var result map[string][]AppAttachment
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).LoadAttachmentsForMessages(ctx, workspaceID, messageIDs)
		return err
	})
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (store *Store) ListPersonalStickersForUser(ctx context.Context, userID string, workspaceID string) ([]PersonalSticker, error) {
	var result []PersonalSticker
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).ListPersonalStickersForUser(ctx, userID, workspaceID)
		return err
	})
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (store *Store) UploadPersonalStickersForUser(ctx context.Context, userID string, workspaceID string, stickers []CreateAttachmentParams) ([]PersonalSticker, error) {
	var result []PersonalSticker
	var txs TxStore
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		txs = store.InTx(tx)
		var err error
		result, err = store.InTx(tx).UploadPersonalStickersForUser(ctx, userID, workspaceID, stickers)
		return err
	})
	if err != nil {
		txs.cleanupUploadedMediaObjects(ctx)
		txs.releaseUploadedMediaObjectTracker()
		return nil, err
	}
	txs.releaseUploadedMediaObjectTracker()
	return result, nil
}

func (store *Store) DeletePersonalStickerForUser(ctx context.Context, userID string, workspaceID string, stickerID string) error {
	return coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		return store.InTx(tx).DeletePersonalStickerForUser(ctx, userID, workspaceID, stickerID)
	})
}

func (store *Store) LoadPersonalStickerForUser(ctx context.Context, userID string, workspaceID string, stickerID string) (AttachmentDownload, error) {
	var result AttachmentDownload
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).LoadPersonalStickerForUser(ctx, userID, workspaceID, stickerID)
		return err
	})
	if err != nil {
		return AttachmentDownload{}, err
	}
	return result, nil
}

func (store *Store) DeleteUnclaimedAttachmentsBefore(ctx context.Context, cutoff time.Time, limit int) (int64, error) {
	var result int64
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).DeleteUnclaimedAttachmentsBefore(ctx, cutoff, limit)
		return err
	})
	if err != nil {
		return 0, err
	}
	return result, nil
}
