package s3

import (
	"fmt"
	"io"

	"github.com/fiskerinc/cloud-services/pkg/utils/envtool"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"

	"github.com/pkg/errors"
)

var instanceS3 Interface
var bucket string = envtool.GetEnv("OTA_UPDATE_BUCKET", "fisker-upload-dev")
var downloadurl = envtool.GetEnv("OTA_UPDATE_DOWNLOAD_URL", "https://upload-dev.fiskerdps.com")

// S3 AWS S3 bucket
type S3 struct {
}

// Interface interface for S3
type Interface interface {
	PutBucket(key string, reader io.Reader, contentType string) (string, error)
}

// PutBucket put file into S3 bucket
func (s *S3) PutBucket(key string, reader io.Reader, contentType string) (string, error) {
	if len(key) > 255 {
		return "", errors.New("S3 key too long")
	}

	sess := session.Must(session.NewSession())
	uploader := s3manager.NewUploader(sess)
	_, err := uploader.Upload(&s3manager.UploadInput{
		Bucket:      aws.String(bucket),
		Key:         aws.String(key),
		Body:        reader,
		ACL:         aws.String("public-read"),
		ContentType: aws.String(contentType),
	})
	if err != nil {
		return "", errors.WithStack(err)
	}

	return fmt.Sprintf("%s/%s", downloadurl, key), nil
}

// GetS3 returns S3 struct
func GetS3() Interface {
	if instanceS3 != nil {
		return instanceS3
	}

	return &S3{}
}

// SetS3Instance set S3 instance to return for mocking
func SetS3Instance(value Interface) {
	instanceS3 = value
}
