package tidbclusterrestart

import (
	"context"
	"fmt"
	"github.com/pingcap/tep/pkg/apis/apiserver"
	"github.com/pingcap/tep/pkg/rbac"
	store "github.com/pingcap/tep/pkg/registry/apiserver"
	"github.com/pingcap/tep/pkg/utils"
	"k8s.io/apimachinery/pkg/api/errors"
	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"
	"time"
)

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 "TiDBClusterRestart"
}

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

func (s *Storage) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
	operatorName := utils.GetAPIUsername(ctx)
	if !rbac.CanOperate(s.store.DB, operatorName, rbac.DeleteAndRestartCluster) {
		return nil, errors.NewForbidden(s.groupResource, operatorName, fmt.Errorf("permission denied"))
	}
	name, _ := request.NamespaceFrom(ctx)
	tc, err := s.store.GetTiDBCluster(name)
	if err != nil {
		if errors.IsNotFound(err) {
			return nil, errors.NewNotFound(s.groupResource, name)
		}
		return nil, errors.NewInternalError(err)
	}

	tc.Spec.TiDB.Annotations["tidb.pingcap.com/restartedAt"] = time.Now().Format(time.RFC3339)
	tc.Spec.PD.Annotations["tidb.pingcap.com/restartedAt"] = time.Now().Format(time.RFC3339)
	tc.Spec.TiKV.Annotations["tidb.pingcap.com/restartedAt"] = time.Now().Format(time.RFC3339)

	if _, err := s.store.TidbClusterClient.PingcapV1alpha1().TidbClusters(name).Update(tc); err != nil {
		msg := fmt.Errorf("failed to restart cluster %s. err: %v", name, err)
		return nil, errors.NewInternalError(msg)
	}

	return obj, nil
}

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