package resourcemanager

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

	"github.com/tidbcloud/observability/pkg/common/errors"
	"github.com/tidbcloud/observability/pkg/common/structs"
	"github.com/tidbcloud/observability/pkg/resourceworker/providers"
	"gopkg.in/yaml.v3"
)

type archivedClusterReaderWriter struct {
	s3Cli providers.S3Client
}

func (p archivedClusterReaderWriter) Archive(ctx context.Context, bucket string, uniqueKey structs.ClusterUniqueKey, archived structs.ArchivedClusterInfo) error {
	content, err := yaml.Marshal(archived)
	if err != nil {
		return errors.Wrap(errors.MarshalError, "", err)
	}
	err = p.s3Cli.Put(ctx, bucket, buildObjectStorageKey(uniqueKey), bytes.NewReader(content))
	if err != nil {
		return errors.Wrap(errors.UnrecognizedError, "archive cluster failed", err)
	}
	return nil
}

func (p archivedClusterReaderWriter) Get(ctx context.Context, bucket string, uniqueKey structs.ClusterUniqueKey) (structs.ArchivedClusterInfo, error) {
	info := structs.ArchivedClusterInfo{}
	out, err := p.s3Cli.Get(ctx, bucket, buildObjectStorageKey(uniqueKey))

	defer func() {
		if out != nil {
			(*out).Close()
		}
	}()
	if err != nil {
		if providers.IsObjectNotFound(err) {
			return info, errors.Wrap(errors.ObjectNotFoundError, fmt.Sprintf("get archived cluster %s failed", uniqueKey.Splice()), err)
		}
		return info, errors.Wrap(errors.UnrecognizedError, fmt.Sprintf("get archived cluster %s failed", uniqueKey.Splice()), err)
	}

	content, err := io.ReadAll(*out)
	if err != nil {
		return info, errors.Wrap(errors.UnrecognizedError, "read archived cluster failed", err)
	}
	err = yaml.Unmarshal(content, &info)
	if err != nil {
		return info, errors.Wrap(errors.UnmarshalError, "get archived cluster failed", err)
	}
	return info, nil
}

const storageKeyTemplate = "archived/%s/cluster.yaml"

func buildObjectStorageKey(uniqueKey structs.ClusterUniqueKey) string {
	return fmt.Sprintf(storageKeyTemplate, uniqueKey.Splice())
}
