package usecase

import (
	"backend/pkg/fileStorage/config"
	"backend/pkg/fileStorage/domain/repository"
	"backend/pkg/fileStorage/domain/usecase"
	errs "backend/pkg/library/errors"
	"context"
	"io"
	"time"
)

type AwsS3FileStorageUseCaseParam struct {
	Conf   *config.Config
	Logger errs.Logger
	Repo   repository.FileStorageRepository
}

type AwsS3FileStorageUseCase struct {
	AwsS3FileStorageUseCaseParam
}

func MustAwsS3FileStorageUseCase(param AwsS3FileStorageUseCaseParam) usecase.FileStorageUseCase {
	return &AwsS3FileStorageUseCase{
		param,
	}
}

func (use *AwsS3FileStorageUseCase) Download(ctx context.Context, objectPath string) ([]byte, error) {
	download, err := use.Repo.Download(ctx, objectPath)
	if err != nil {
		e := errs.SvcThirdPartyErrorL(use.Logger, []errs.LogField{
			{Key: "path", Val: objectPath},
			{Key: "action", Val: "AwsS3FileStorageUseCase.Download"},
			{Key: "error", Val: err.Error()},
		}, "s3 - download object failed").Wrap(err)

		return nil, e
	}

	return download, nil
}

func (use *AwsS3FileStorageUseCase) Move(ctx context.Context, objectPath string, destinationPath string) error {
	err := use.Repo.Move(ctx, objectPath, destinationPath)
	if err != nil {
		e := errs.SvcThirdPartyErrorL(use.Logger, []errs.LogField{
			{Key: "source", Val: objectPath},
			{Key: "destination", Val: destinationPath},
			{Key: "action", Val: "AwsS3FileStorageUseCase.Move"},
			{Key: "error", Val: err.Error()},
		}, "s3 - s3 - move object failed").Wrap(err)

		return e
	}

	return nil
}

func (use *AwsS3FileStorageUseCase) Delete(ctx context.Context, objectPath string) error {
	err := use.Repo.Delete(ctx, objectPath)
	if err != nil {
		e := errs.SvcThirdPartyErrorL(use.Logger, []errs.LogField{
			{Key: "path", Val: objectPath},
			{Key: "action", Val: "AwsS3FileStorageUseCase.Delete"},
			{Key: "error", Val: err.Error()},
		}, "s3 - delete object failed").Wrap(err)

		return e
	}

	return nil
}

func (use *AwsS3FileStorageUseCase) Exists(ctx context.Context, objectPath string) (bool, error) {
	ex, err := use.Repo.Exists(ctx, objectPath)
	if err != nil {
		e := errs.SvcThirdPartyErrorL(use.Logger, []errs.LogField{
			{Key: "path", Val: objectPath},
			{Key: "error", Val: err.Error()},
		}, "s3 - check exists object failed").Wrap(err)

		return false, e
	}

	return ex, nil
}

func (use *AwsS3FileStorageUseCase) DeleteDirectory(ctx context.Context, directoryPath string) error {
	err := use.Repo.DeleteDirectory(ctx, directoryPath)

	return errs.SvcThirdPartyErrorL(
		use.Logger,
		[]errs.LogField{
			{Key: "directory", Val: directoryPath},
			{Key: "action", Val: "AwsS3FileStorageUseCase.DeleteDirectory"},
			{Key: "error", Val: err.Error()},
		},
		"s3 - failed to list objects in folder",
	).Wrap(err)
}

func (use *AwsS3FileStorageUseCase) UploadWithTTL(ctx context.Context, content io.Reader, objectPath string, expires *time.Time) error {
	err := use.Repo.UploadWithTTL(ctx, content, objectPath, expires)
	if err != nil {
		e := errs.SvcThirdPartyErrorL(
			use.Logger,
			[]errs.LogField{
				{Key: "action", Val: "AwsS3FileStorageUseCase.DeleteDirectory"},
				{Key: "error", Val: err.Error()},
			},
			"s3 - failed to list objects in folder")

		return e
	}

	return nil
}

func (use *AwsS3FileStorageUseCase) UploadFromData(ctx context.Context, data []byte, objectPath string, contentType string) error {
	err := use.Repo.UploadFromData(ctx, data, objectPath, contentType)
	if err != nil {
		e := errs.SvcThirdPartyErrorL(
			use.Logger,
			[]errs.LogField{
				{Key: "path", Val: objectPath},
				{Key: "action", Val: "AwsS3FileStorageUseCase.UploadFromData"},
				{Key: "error", Val: err.Error()},
			},
			"s3 - upload object failed")

		return e
	}

	return nil
}

func (use *AwsS3FileStorageUseCase) UploadFromPath(ctx context.Context, localFilePath string, objectPath string) error {
	err := use.Repo.UploadFromPath(ctx, localFilePath, objectPath)
	if err != nil {
		e := errs.SvcThirdPartyErrorL(
			use.Logger,
			[]errs.LogField{
				{Key: "localPath", Val: localFilePath},
				{Key: "action", Val: "AwsS3FileStorageUseCase.UploadFromPath"},
				{Key: "error", Val: err.Error()},
			},
			"s3 - upload object failed")

		return e
	}

	return nil
}

func (use *AwsS3FileStorageUseCase) GetPublicURL(ctx context.Context, objectPath string) string {
	return use.Repo.GetPublicURL(ctx, objectPath)
}
