package checker

import (
	"context"
	"time"

	"github.com/onsi/gomega"
	"github.com/pingcap/log"
	logsearch "github.com/pingcap/test-infra/sdk/pkg/logs"
	"github.com/pingcap/test-infra/sdk/resource"
	"go.uber.org/zap"
	"golang.org/x/sync/errgroup"

	"github.com/pingcap/endless/pkg/matcher"
	"github.com/pingcap/endless/pkg/matcher/metrics"
	"github.com/pingcap/endless/pkg/util"
)

func CommonCheck(ctx context.Context, tc resource.TiDBCluster, g *errgroup.Group, duration time.Duration,
	histograms map[string]*Histogram) {
	matcher.SetDefaultConsistentlyWithMetricsDuration(duration)
	g.Go(util.WithGinkgoRecover(func() {
		matcher.ConsistentlyWithMetrics(tc).
			ShouldNot(metrics.TiFlashMvccSnapshotLifetimeMoreThan(1800).WithCtx(ctx))
	}))

	g.Go(util.WithGinkgoRecover(func() {
		matcher.ConsistentlyWithMetrics(tc).
			ShouldNot(metrics.TiFlashRestart().WithCtx(ctx))
	}))

	g.Go(util.WithGinkgoRecover(func() {
		TiFlashCrashChecker(tc, duration)
	}))

	for _, h := range histograms {
		var htmp = h
		log.Info("start check latency", zap.String("query name", h.Name))
		g.Go(util.WithGinkgoRecover(func() {
			time.Sleep(5 * time.Minute)
			gomega.Consistently(MeanLatency, duration, 30*time.Second).ShouldNot(LatencyIncreasedMoreThanOffset(
				htmp, 20, 20, 10, 0.2, 0).WithCtx(ctx))
		}))
	}
}

func CommonCheckWithoutLatencyAndRestart(ctx context.Context, tc resource.TiDBCluster, g *errgroup.Group, duration time.Duration) {
	matcher.SetDefaultConsistentlyWithMetricsDuration(duration)
	g.Go(util.WithGinkgoRecover(func() {
		matcher.ConsistentlyWithMetrics(tc).
			ShouldNot(metrics.TiFlashMvccSnapshotLifetimeMoreThan(1800).WithCtx(ctx))
	}))

	g.Go(util.WithGinkgoRecover(func() {
		TiFlashCrashChecker(tc, duration)
	}))
}

// 只检索 server.log 及其压缩包
// 在实践中发现一些非 BaseDaemon 关键字的 crash，如 https://github.com/pingcap/tiflash/issues/5230
func TiFlashCrashChecker(tc resource.TiDBCluster, duration time.Duration) {
	ctx := context.Background()
	gomega.Consistently(func() int {
		res, err := tc.SearchLog(ctx, resource.TiDBClusterSearchLogOptions{
			Target:    resource.TiFlash,
			Levels:    []logsearch.LogLevel{logsearch.LogLevelError},
			StartTime: time.Now().Add(-5 * time.Minute),
			EndTime:   time.Now(),
			Patterns:  []string{"BaseDaemon"},
		})
		if err != nil {
			log.Error("tiflash checker search log error", zap.Error(err))
			return 0
		}
		if len(res) != 0 {
			log.Error("tiflash crash", zap.Strings("log", res))
		}
		return len(res)
	}, duration, 3*time.Minute).Should(gomega.BeZero())
}
