package remotefileupload

import (
	"bytes"
	"fmt"
	"net/http"
	"path/filepath"

	"github.com/fiskerinc/cloud-services/pkg/logger"
	"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"
)

var (
	awsBucketRegion  = envtool.GetEnv("AWS_REGION", "us-west-2")
	awsBucketName    = envtool.GetEnv("AWS_BUCKET_NAME", "fisker-data-test")
	awsFileExtension = envtool.GetEnv("AWS_FILE_EXTENSION", ".csv")
)

// NewS3Uploader creates a new S3Uploader instance using env variables
// requires ENV vars: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
func NewS3Uploader(awsBucketName string) Uploader {
	var uploader *S3Uploader

	cfg := aws.NewConfig().WithRegion(awsBucketRegion)
	sess := session.Must(session.NewSession())

	uploader = &S3Uploader{
		service:       s3.New(sess, cfg),
		bucketRegion:  awsBucketRegion,
		bucketName:    awsBucketName,
		fileExtension: awsFileExtension,
	}
	return uploader
}

type S3Uploader struct {
	service       *s3.S3
	bucketRegion  string
	bucketName    string
	fileExtension string
}

// Upload creates a new object within S3 under the designated path
//
//	objects can be up to 15MB before requiring multi-upload
func (s *S3Uploader) Upload(block []byte, logValue LogPayload, filePath ...string) (string, error) {
	fileType := http.DetectContentType(block)

	path := s.s3ObjectURL(filePath)
	input := &s3.PutObjectInput{
		Bucket:      aws.String(s.bucketName),
		Key:         aws.String(path),
		ContentType: aws.String(fileType),
		Body:        bytes.NewReader(block),
	}

	logger.Debug().Str(logValue.Title, logValue.Value).Msgf("sending block of length %d to aws object: %s", len(block), path)
	_, err := s.service.PutObject(input)
	if err != nil {
		return "", err
	}

	logger.Debug().Str(logValue.Title, logValue.Value).Msgf("upload complete")
	return path, nil
}

// s3ObjectURL is the URL formatter for an S3 object
func (s *S3Uploader) s3ObjectURL(filePath []string) string {
	fileName := fmt.Sprintf("%s%s", "raw", s.fileExtension)
	finalPath := filepath.Join(filepath.Join(filePath...), fileName)
	return finalPath
}
