package s3storage

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"sync"

	"cloud.google.com/go/storage"
	log "github.com/sirupsen/logrus"
	"github.com/tidbcloud/observability/pkg/resourceworker/providers/gcp/gcs"
)

var csonce sync.Once
var cscli *storage.Client

type CloudStorageClient struct {
	cli     gcs.CloudStorageClient
	project string
	region  string
}

func (cs *CloudStorageClient) GetLarge(ctx context.Context, bucketName string, objectName string) (*io.ReadCloser, error) {
	return cs.Get(ctx, bucketName, objectName)
}

func (cs *CloudStorageClient) PutLarge(ctx context.Context, bucketName string, objectName string, reader *bytes.Reader) error {
	return cs.Put(ctx, bucketName, objectName, reader)
}

func NewCloudStorage(project string, region string) *CloudStorageClient {
	csonce.Do(func() {
		cli, err := storage.NewClient(context.Background())
		if err != nil {
			//we will panic at first use if any error found
			panic(fmt.Sprintf("create cloud storage client failed in gcp vendor err: %s", err))
		}
		cscli = cli
	})
	return &CloudStorageClient{
		cli:     gcs.StorageClientWarp{Client: cscli},
		project: project,
		region:  region,
	}
}

func (cs *CloudStorageClient) Get(ctx context.Context, bucketName string, objectName string) (*io.ReadCloser, error) {
	reader, err := cs.cli.Bucket(bucketName).Object(objectName).NewReader(ctx)
	if err != nil {
		log.Errorf(err.Error())
		return nil, err
	}
	var r io.ReadCloser = reader
	return &r, nil
}

func (cs *CloudStorageClient) Put(ctx context.Context, bucketName string, objectName string, reader *bytes.Reader) error {
	writer := cs.cli.Bucket(bucketName).Object(objectName).NewWriter(ctx)
	defer writer.Close()
	_, err := reader.WriteTo(writer)
	if err != nil {
		log.Errorf(err.Error())
		return err
	}
	// Close the Writer to complete the upload
	if err := writer.Close(); err != nil {
		return fmt.Errorf("Writer.Close: %w", err)
	}
	return nil
}
