package impl

import (
	"context"

	"github.com/pingcap/log"
	"go.uber.org/zap"

	"github.com/pingcap-inc/clinic/pkg/ngm/statements/aggregate"
	"github.com/pingcap-inc/clinic/pkg/ngm/statements/api"
	"github.com/pingcap-inc/clinic/pkg/ngm/statements/filter"
	"github.com/pingcap-inc/clinic/pkg/ngm/statements/group"
	"github.com/pingcap-inc/clinic/pkg/ngm/statements/load"
)

func (s *StatementImpl) Plans(ctx context.Context, param *api.PlansParam) ([]*api.Model, error) {
	loadParam := &load.LoadParam{
		Env:           s.env,
		Provider:      param.Provider,
		Region:        param.Region,
		OrgID:         param.OrgID,
		ProjectID:     param.ProjectID,
		ClusterID:     param.ClusterID,
		SharedTier:    param.SharedTier,
		StorageBucket: param.StorageBucket,
		StoragePrefix: param.StoragePrefix,
		StartUnixSec:  param.StartUnixSec,
		EndUnixSec:    param.EndUnixSec,
	}
	rows, err := load.Load(ctx, loadParam, s.sf, s.cache)
	if err != nil {
		log.Warn("load failed", zap.Error(err))
		return nil, ErrLoadFailed
	}

	flt := filter.Filters(
		filter.ByTimeRange(param.StartUnixSec, param.EndUnixSec),
		filter.ByDigest(param.Digest),
		filter.ByExecSchema(param.SchemaName),
		filter.DiscardInternalSQL(),
	)
	grp := group.ByPlanDigest()
	agg := aggregate.AggregatorFactories(
		getStmtAggFactories([]string{
			"plan_digest",
			"schema_name",
			"digest_text",
			"digest",
			"sum_latency",
			"max_latency",
			"min_latency",
			"avg_latency",
			"exec_count",
			"avg_mem",
			"max_mem",
			"stmt_type",
			"plan_hint",
			"plan_in_binding",
			"summary_begin_time",
			"summary_end_time",
			"last_seen",
		}),
	)

	models, err := Execute(ctx, rows, flt, grp, agg)
	if err != nil {
		log.Warn("execute failed", zap.Error(err))
		return nil, ErrExecuteFailed
	}
	sortBySumLatency(models)
	return models, nil
}
