package failedtidbcluster

import (
	"context"
	"fmt"
	"github.com/pingcap/log"
	"github.com/pingcap/tep/pkg/apis/apiserver"
	"github.com/pingcap/tep/pkg/controller"
	"github.com/pingcap/tep/pkg/operator"
	store "github.com/pingcap/tep/pkg/registry/apiserver"
	"github.com/pingcap/tep/pkg/utils"
	"go.uber.org/zap"
	"k8s.io/apimachinery/pkg/api/errors"
	metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
)

type Storage struct {
	store *store.Store
}

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

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

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

func (s *Storage) List(ctx context.Context, options *metainternalversion.ListOptions, extraOptions runtime.Object) (runtime.Object, error) {
	opts := metav1.ListOptions{}
	opts.LabelSelector = fmt.Sprintf("%s=%s", operator.CreatedByLabelKey, operator.CreatedByLabelVal)

	tcl, err := s.store.Controller().GetTidbClusters(metav1.NamespaceAll, opts)
	if err != nil {
		log.Error("failed to get instance list", zap.Error(err))
		return nil, errors.NewInternalError(err)
	}
	tidbClusters := tcl.Items
	var failedInstances []apiserver.FailedTiDBCluster

	if len(tidbClusters) == 0 {
		return &apiserver.FailedTiDBClusterList{
			Items: []apiserver.FailedTiDBCluster{},
			Total: 0,
		}, nil
	}

	for _, tc := range tidbClusters {
		instanceStatus, reason := s.store.Controller().GetClusterStatus(&tc)
		if instanceStatus == controller.InstanceStatusStatusFailed {
			name, tags := s.store.Controller().GetNameAndTags(&tc)
			failedInstance := apiserver.FailedTiDBCluster{
				ClusterName: name,
				Tags:        tags,
				Reasons:     []string{reason},
			}
			failedInstance.Name = tc.Namespace
			failedInstances = append(failedInstances, failedInstance)
		}
	}

	listOpts := extraOptions.(*apiserver.ListOptions)
	res := &apiserver.FailedTiDBClusterList{
		Total: int64(len(failedInstances)),
		Items: utils.Pagination(listOpts.Page, listOpts.ItemsPerPage, failedInstances).([]apiserver.FailedTiDBCluster),
	}
	return res, nil
}

func (s *Storage) NewList() runtime.Object {
	return &apiserver.FailedTiDBClusterList{}
}

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

func (s *Storage) NewExtraListOptions() runtime.Object {
	return &apiserver.ListOptions{}
}
