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) Detail(ctx context.Context, param *api.DetailParam) (*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.ByPlanDigest(param.Plans),
		filter.DiscardInternalSQL(),
		filter.DiscardCloudAdminUser(),
	)
	grp := group.None()
	agg := aggregate.AggregatorFactories(allAggFactories())

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

	if len(models) > 1 {
		log.Error("unexpected multiple models",
			zap.Int("len", len(models)),
			zap.Any("param", param),
			zap.Any("models", models))
		return nil, nil
	}

	if len(models) == 0 {
		return nil, nil
	}
	return models[0], nil
}
