package server

import (
	"context"
	"io"
	"net/url"
	"os"

	"cloud.google.com/go/storage"
	"github.com/pingcap/errors"
)

var _ LogHandler = &GCSHandler{}

// GCSHandler handle pushing log to s3.
type GCSHandler struct {
	Config
	bucket string
	client *storage.Client
}

func NewGCSHandler(config Config) (*GCSHandler, error) {
	h := &GCSHandler{
		Config: config,
	}

	err := h.buildGCSClient(context.Background())
	if err != nil {
		return nil, errors.Annotate(err, "failed to build storage client")
	}

	u, err := url.Parse(h.BucketURL)
	if err != nil {
		return nil, errors.Annotatef(err, "invalid url %q", h.BucketURL)
	}

	h.bucket = u.Host

	return h, nil
}

func (h *GCSHandler) buildGCSClient(ctx context.Context) error {
	// env GOOGLE_APPLICATION_CREDENTIALS should be set
	// ref: https://cloud.google.com/docs/authentication/getting-started
	client, err := storage.NewClient(ctx)
	if err != nil {
		return errors.Annotate(err, "failed to new storage client")
	}

	h.client = client
	return nil
}

// Push implements LogHandler interface.
func (h *GCSHandler) Push(ctx context.Context, fname string, targetKey string) (err error) {
	file, err := os.Open(fname)
	if err != nil {
		return errors.Annotatef(err, "failed to open file %q", fname)
	}
	defer file.Close()

	wc := h.client.Bucket(h.bucket).Object(targetKey).NewWriter(ctx)
	_, err = io.Copy(wc, file)
	if err != nil {
		return errors.Annotate(err, "failed to io.Copy")
	}

	err = wc.Close()
	if err != nil {
		return errors.Annotate(err, "failed to close object writer")
	}

	return nil
}

// Close implements LogHandler interface.
func (h *GCSHandler) Close() {
	h.client.Close()
}
