package operateevent

import (
	"context"
	"github.com/pingcap/tep/db/entity"
	"github.com/pingcap/tep/pkg/apis/apiserver"
	store "github.com/pingcap/tep/pkg/registry/apiserver"
	"github.com/pingcap/tep/pkg/utils"
	"k8s.io/apimachinery/pkg/api/errors"
	metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apiserver/pkg/endpoints/request"
)

type Storage struct {
	store *store.Store
}

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

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

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

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

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

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

func (s *Storage) List(ctx context.Context, options *metainternalversion.ListOptions, extraOptions runtime.Object) (runtime.Object, error) {
	logOptions := extraOptions.(*apiserver.OperateEventListOptions)
	query := &OperationLogQuery{
		From:           utils.GetStartIndex(logOptions.Page, logOptions.ItemsPerPage),
		Size:           utils.GetSize(logOptions.ItemsPerPage),
		StartTimeInSec: logOptions.StartTimeInSec,
		EndTimeInSec:   logOptions.EndTimeInSec,
		ManagementType: logOptions.ManagementType,
		OperationType:  logOptions.OperationType,
	}
	if logOptions.Format == "csv" {
		userID := ""
		if user, found := request.UserFrom(ctx); found {
			userID = user.GetUID()
		}
		utils.AddEventAndLogError(s.store.DB, &utils.Event{
			UserID:         userID,
			Payload:        "download platform operation log",
			ManagementType: entity.PlatformManagement,
			OperationType:  entity.OperateOperation,
		})
		return s.downLoadOperateEvents(query)
	}
	sortBy := utils.ParseSortByFiled(logOptions.SortBy)
	if len(sortBy) >= 1 {
		if dbName, found := sortableFiled[sortBy[0].Field]; found {
			query.OrderBy = dbName
			query.Desc = sortBy[0].Desc
		} else {
			return nil, errors.NewBadRequest("unsupported sort by field")
		}
	} else {
		query.OrderBy = operationTimeDBColumnName
		query.Desc = true
	}
	items, total, err := s.getAllOperationEvents(query)
	if err != nil {
		return nil, errors.NewInternalError(err)
	}
	return &apiserver.OperateEventList{
		Items: items,
		Total: total,
	}, nil
}
