package slowlog

import (
	"context"
	"fmt"
	"github.com/pingcap/tep/pkg/utils"
	"strings"
	"time"

	"github.com/elastic/go-elasticsearch/v6"
	"github.com/pingcap/log"
	query2 "github.com/pingcap/tep/pkg/utils/es/query"
	"github.com/wushilin/stream"
	"go.uber.org/zap"
)

type slowQuery struct {
	from      int
	size      int
	startTime string
	endTime   string
	namespace string
}

type Query func(q *slowQuery)

func NewSlowQuery(q ...Query) *slowQuery {
	tidbQ := &slowQuery{}
	stream.FromArray(q).Each(func(f interface{}) {
		f.(Query)(tidbQ)
	})

	return tidbQ
}

func From(from int) Query {
	if from < 0 {
		from = 0
	}

	return func(q *slowQuery) {
		q.from = from
	}
}

func Size(size int) Query {
	if size <= 0 {
		size = 10
	}

	return func(q *slowQuery) {
		q.size = size
	}
}

func StartTimeInSec(startTimeInSec int64) Query {
	if startTimeInSec <= 0 {
		startTimeInSec = time.Now().Unix() - 15*60
	}

	return func(q *slowQuery) {
		q.startTime = query2.ConvertTimeStamp(startTimeInSec)
	}
}

func EndTimeInSec(endTimeInSec int64) Query {
	if endTimeInSec <= 0 {
		endTimeInSec = time.Now().Unix()
	}

	return func(q *slowQuery) {
		q.endTime = query2.ConvertTimeStamp(endTimeInSec)
	}
}

func NameSpace(namespace string) Query {
	return func(q *slowQuery) {
		q.namespace = namespace
	}
}

func (q *slowQuery) Do(client *elasticsearch.Client, indexPrefix string) (*query2.QueryResponse, error) {
	qb := query2.NewQueryBuilder().
		AddEqual("kubernetes.namespace_name", q.namespace).
		AddRange("@timestamp", q.startTime, q.endTime).
		Sort("@timestamp", true).
		From(q.from).
		Size(q.size).
		BuildQuery()

	////currently, the index name is not made
	res, err := client.Search(
		client.Search.WithContext(context.Background()),
		client.Search.WithIndex(fmt.Sprintf("%s*", indexPrefix)),
		client.Search.WithBody(strings.NewReader(qb)),
		client.Search.WithPretty(),
	)

	if err != nil {
		log.Error("Query from es failed", zap.Error(err))
		return nil, err
	}
	defer utils.CallDeferMethod(res.Body.Close, "close response body failed")
	return query2.NewResponse(res.Body), nil
}
