package account

import (
	"context"

	"github.com/tidbcloud/infra-provider/pkg/k8s"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/common/constants"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/common/models"
	rsconfig "github.com/tidbcloud/infra-provider/regional-server/pkg/config"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type SharedBucketReaderWriter interface {
	SharedBucketReader
	SharedBucketWriter
}

type SharedBucketReader interface {
	GetBinding(ctx context.Context, target models.SharedBucketBindingTarget) (string, error)
}

type SharedBucketWriter interface {
	Bind(ctx context.Context, binding models.SharedBucketInfo, target models.SharedBucketBindingTarget) error
	Unbind(ctx context.Context, target models.SharedBucketBindingTarget) error
}

func NewSharedBucketReaderWriter(cli client.Client, config rsconfig.RootConfig) SharedBucketReaderWriter {
	return &sharedBucketReaderWriter{
		sharedBucketReader: sharedBucketReader{cli},
		sharedBucketWriter: sharedBucketWriter{cli, config},
	}
}

func NewSharedBucketReader(cli client.Client) SharedBucketReader {
	return &sharedBucketReader{
		readCli: cli,
	}
}

func NewSharedBucketWriter(cli client.Client, config rsconfig.RootConfig) SharedBucketWriter {
	return &sharedBucketWriter{
		cli:    cli,
		config: config,
	}
}

type sharedBucketReaderWriter struct {
	sharedBucketReader
	sharedBucketWriter
}

type sharedBucketWriter struct {
	cli    client.Client
	config rsconfig.RootConfig
}

func (a sharedBucketWriter) Bind(ctx context.Context, sharedBucket models.SharedBucketInfo, target models.SharedBucketBindingTarget) error {
	configData := map[string]string{}
	configData[constants.SharedBucketConfigMapDefaultKey] = sharedBucket.GetKey()

	configMap := &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: constants.DataPlaneAccountNamespace,
			Name:      target.UniqueTargetName(),
			Labels:    a.config.ResourceLabels,
		},
		Data: configData,
	}
	return k8s.Apply(ctx, a.cli, configMap)
}

func (a sharedBucketWriter) Unbind(ctx context.Context, target models.SharedBucketBindingTarget) error {
	configMap := &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: constants.DataPlaneAccountNamespace,
			Name:      target.UniqueTargetName(),
		},
	}
	return client.IgnoreNotFound(a.cli.Delete(ctx, configMap))
}

type sharedBucketReader struct {
	readCli client.Reader
}

func (a sharedBucketReader) GetBinding(ctx context.Context, target models.SharedBucketBindingTarget) (string, error) {
	configMap := new(v1.ConfigMap)
	err := a.readCli.Get(ctx, client.ObjectKey{
		Namespace: constants.DataPlaneAccountNamespace,
		Name:      target.UniqueTargetName(),
	}, configMap)

	if err != nil {
		if client.IgnoreNotFound(err) != nil {
			return "", err
		}
		return "", nil
	}
	bindingSharedBucketKey := configMap.Data[constants.SharedBucketConfigMapDefaultKey]

	return bindingSharedBucketKey, nil
}
