package tidbclusterconfig

import (
	"context"
	"reflect"

	"github.com/pingcap/tep/pkg/apis/apiserver"
	store "github.com/pingcap/tep/pkg/registry/apiserver"
	"github.com/pingcap/tep/pkg/utils"
	"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apiserver/pkg/endpoints/request"
	"k8s.io/apiserver/pkg/registry/rest"
)

type Storage struct {
	store         *store.Store
	groupResource schema.GroupResource
}

func NewStorage(store *store.Store, groupResource schema.GroupResource) *Storage {
	return &Storage{
		store:         store,
		groupResource: groupResource,
	}
}

func (s *Storage) Kind() string {
	return "TiDBClusterConfig"
}

func (s *Storage) New() runtime.Object {
	return &apiserver.TiDBClusterConfig{}
}

func (s *Storage) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
	var err error
	var namespace string
	var tc *v1alpha1.TidbCluster
	namespace = request.NamespaceValue(ctx)
	if tc, err = s.store.GetTiDBCluster(name); err != nil {
		return nil, err
	}

	tidbConfType := reflect.TypeOf(v1alpha1.TiDBConfig{})
	tidbConf := reflect.New(tidbConfType)
	utils.RecursiveDefineObject(tidbConfType, tidbConf.Elem())
	tidbConfig := tidbConf.Interface().(*v1alpha1.TiDBConfig)

	tikvConfType := reflect.TypeOf(v1alpha1.TiKVConfig{})
	tikvConf := reflect.New(tikvConfType)
	utils.RecursiveDefineObject(tikvConfType, tikvConf.Elem())
	tikvConfig := tikvConf.Interface().(*v1alpha1.TiKVConfig)

	pdConfType := reflect.TypeOf(v1alpha1.PDConfig{})
	pdConf := reflect.New(pdConfType)
	utils.RecursiveDefineObject(pdConfType, pdConf.Elem())
	pdConfig := pdConf.Interface().(*v1alpha1.PDConfig)

	config := &apiserver.TiDBClusterConfig{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: namespace,
			UID:       tc.UID,
		},
		TiDBConfig: tidbConfig,
		TiKVConfig: tikvConfig,
		PDConfig:   pdConfig,
	}

	return config, nil
}

func (s *Storage) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
	return nil, true, nil
}

func (s *Storage) NamespaceScoped() bool {
	return true
}
