package cdn

import (
	"io"
	"strings"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/pingcap/dbaas/central/config"
	"github.com/pingcap/errors"
)

type CDNHandler interface {
	UploadFile(path string, size int64, file io.ReadSeekCloser) error
	GetCDNFile(path string) (*FileObject, error)
}

type S3CDNHandlerImpl struct{}
type MockCDNHandler struct{}

type FileObject struct {
	File          io.ReadCloser
	ContentLength int64
}

func (*S3CDNHandlerImpl) UploadFile(path string, size int64, file io.ReadSeekCloser) error {
	defer file.Close() // nolint: errcheck
	sess, err := session.NewSession()
	if err != nil {
		return errors.Annotate(err, "create s3 client error")
	}
	client := s3.New(sess)
	path = path + config.Global().ServerConfig.CDNBucketPathPrefix

	_, err = client.PutObject(&s3.PutObjectInput{
		Bucket:        &config.Global().ServerConfig.CDNBucket,
		Key:           &path,
		Body:          file,
		ContentLength: &size,
	})
	if err != nil {
		return errors.Annotate(err, "failed to upload object to s3")
	}
	return nil
}

func (*S3CDNHandlerImpl) GetCDNFile(path string) (*FileObject, error) {
	sess, err := session.NewSession()
	if err != nil {
		return nil, errors.Annotate(err, "create s3 client error")
	}
	client := s3.New(sess)
	path = path + config.Global().ServerConfig.CDNBucketPathPrefix

	input := &s3.GetObjectInput{
		Bucket: &config.Global().ServerConfig.CDNBucket,
		Key:    &path,
	}

	object, err := client.GetObject(input)
	if err != nil {
		return nil, errors.Annotate(err, "get s3 object error")
	}

	return &FileObject{
		File:          object.Body,
		ContentLength: *object.ContentLength,
	}, nil
}

func (*MockCDNHandler) UploadFile(path string, size int64, file io.ReadSeekCloser) error {
	defer file.Close() // nolint: errcheck
	return nil
}

func (*MockCDNHandler) GetCDNFile(path string) (*FileObject, error) {
	return &FileObject{
		File:          io.NopCloser(strings.NewReader("")),
		ContentLength: 0,
	}, nil
}

func Get() CDNHandler {
	if config.Global().ServerConfig.EnableCDNBucket {
		return &S3CDNHandlerImpl{}
	}
	return &MockCDNHandler{}
}
