package platformmessage

import (
	"bytes"
	"context"
	"github.com/go-openapi/strfmt"
	"github.com/pingcap/tep/db/entity"
	"github.com/pingcap/tep/pkg/apis/apiserver"
	"github.com/pingcap/tep/pkg/i18n"
	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"
	"time"
)

type Storage struct {
	store *store.Store
}

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

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

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

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

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

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

func (s *Storage) List(ctx context.Context, options *metainternalversion.ListOptions, extraOptions runtime.Object) (runtime.Object, error) {
	listOptions := extraOptions.(*apiserver.PlatformMessageListOptions)
	query := &query{
		From:           utils.GetStartIndex(listOptions.Page, listOptions.ItemsPerPage),
		Size:           utils.GetSize(listOptions.ItemsPerPage),
		StartTimeInSec: listOptions.StartTimeInSec,
		EndTimeInSec:   listOptions.EndTimeInSec,
		Type:           listOptions.Type,
		Lang:           i18n.LangZHCN,
	}
	if len(listOptions.Lang) > 0 {
		query.Lang = i18n.LANG(listOptions.Lang)
	}
	sortBy := utils.ParseSortByFiled(listOptions.SortBy)
	if len(sortBy) >= 1 {
		query.OrderBy = sortBy[0].Field
		query.Desc = sortBy[0].Desc
	} else {
		query.OrderBy = "time"
		query.Desc = true
	}
	items, total, err := s.getAllPlatformMessages(query)
	if err != nil {
		return nil, errors.NewInternalError(err)
	}
	return &apiserver.PlatformMessageList{
		Items: items,
		Total: total,
	}, nil
}

type query struct {
	StartTimeInSec int64
	EndTimeInSec   int64
	Lang           i18n.LANG
	Type           string
	From           int
	Size           int
	OrderBy        string
	Desc           bool
}

func (s *Storage) getAllPlatformMessages(query *query) ([]apiserver.PlatformMessage, int64, error) {
	where, values := buildQuery(query)
	var messages []entity.Message
	var total int64
	db := s.store.DB.Table("message").Where(where, values...).Count(&total).
		Limit(query.Size).Offset(query.From).
		Order(utils.GetGORMSortByExpression(query.OrderBy, query.Desc)).
		Find(&messages)
	apiItems := make([]apiserver.PlatformMessage, len(messages))
	for index, item := range messages {
		apiItems[index] = apiserver.PlatformMessage{
			Type:    item.Type,
			Time:    strfmt.DateTime(time.Unix(item.Time, 0)).String(),
			Content: i18n.PlatformMessage.Format(query.Lang, i18n.TemplateID(item.ContentTemplateID), item.TemplateArgs),
		}
	}
	return apiItems, total, db.Error
}

func buildQuery(query *query) (string, []interface{}) {
	var values []interface{}
	where := bytes.Buffer{}
	where.WriteString(" 1=1  ")
	if query.Type != "" {
		where.WriteString(" and type=? ")
		values = append(values, query.Type)
	}
	if query.StartTimeInSec > 0 {
		where.WriteString(" and time >= ? ")
		values = append(values, query.StartTimeInSec)
	}
	if query.EndTimeInSec > 0 {
		where.WriteString(" and time <= ? ")
		values = append(values, query.EndTimeInSec)
	}
	return where.String(), values
}
