package model

import (
	"fmt"
	"testing"
	"time"

	"github.com/onsi/gomega"
	"gorm.io/gorm"

	"github.com/pingcap-inc/clinic/pkg/db"
)

func TestReportBacklogBatchQueries(t *testing.T) {
	g := gomega.NewWithT(t)
	prefix := fmt.Sprintf("report-batch-%d", time.Now().UnixNano())
	base := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)

	healthReports := []*db.HealthReport{
		newHealthReportBatchRecord(prefix+"-health-old", db.StatusPending, base.Add(0*time.Minute)),
		newHealthReportBatchRecord(prefix+"-health-success", db.StatusSuccess, base.Add(1*time.Minute)),
		newHealthReportBatchRecord(prefix+"-health-running", db.StatusRunning, base.Add(2*time.Minute)),
		newHealthReportBatchRecord(prefix+"-health-new", db.StatusPending, base.Add(3*time.Minute)),
	}
	for _, report := range healthReports {
		g.Expect(InsertOrUpdateReport(report)).To(gomega.Succeed())
	}
	t.Cleanup(func() {
		for _, report := range healthReports {
			_ = DeleteHealthReportByID(report.FileUUID)
		}
	})

	healthCount, err := CountPendingOrRunningHealthReportJobs([]string{prefix + "-health-old"})
	g.Expect(err).To(gomega.Succeed())
	g.Expect(healthCount).To(gomega.BeNumerically(">=", 2))
	var healthBatch []*db.HealthReport
	g.Expect(FetchPendingOrRunningHealthReportJobsBatch(&healthBatch, 1, []string{prefix + "-health-old"})).To(gomega.Succeed())
	g.Expect(healthBatch).To(gomega.HaveLen(1))
	g.Expect(healthBatch[0].FileUUID).To(gomega.Equal(prefix + "-health-running"))

	comparisonReports := []*db.ComparisonReport{
		newComparisonReportBatchRecord(prefix+"-comparison-old", db.StatusPending, base.Add(0*time.Minute)),
		newComparisonReportBatchRecord(prefix+"-comparison-success", db.StatusSuccess, base.Add(1*time.Minute)),
		newComparisonReportBatchRecord(prefix+"-comparison-running", db.StatusRunning, base.Add(2*time.Minute)),
		newComparisonReportBatchRecord(prefix+"-comparison-new", db.StatusPending, base.Add(3*time.Minute)),
	}
	for _, report := range comparisonReports {
		_, err := InsertOrUpdateComparisonReport(report)
		g.Expect(err).To(gomega.Succeed())
	}
	t.Cleanup(func() {
		for _, report := range comparisonReports {
			_ = HideComparisonReportByID(report.ID)
		}
	})

	comparisonCount, err := CountPendingOrRunningComparisonJobs([]uint{comparisonReports[0].ID})
	g.Expect(err).To(gomega.Succeed())
	g.Expect(comparisonCount).To(gomega.BeNumerically(">=", 2))
	var comparisonBatch []*db.ComparisonReport
	g.Expect(FetchPendingOrRunningComparisonJobsBatch(&comparisonBatch, 1, []uint{comparisonReports[0].ID})).To(gomega.Succeed())
	g.Expect(comparisonBatch).To(gomega.HaveLen(1))
	g.Expect(comparisonBatch[0].Hash).To(gomega.Equal(prefix + "-comparison-running"))

	reports := []*db.Report{
		newReportBatchRecord(prefix+"-report-old", db.StatusPending, base.Add(0*time.Minute)),
		newReportBatchRecord(prefix+"-report-running", db.StatusRunning, base.Add(1*time.Minute)),
		newReportBatchRecord(prefix+"-report-new", db.StatusPending, base.Add(2*time.Minute)),
	}
	for _, report := range reports {
		g.Expect(InsertReport(report)).To(gomega.Succeed())
	}
	t.Cleanup(func() {
		for _, report := range reports {
			_ = DeleteReportByUUID(report.UUID)
		}
	})

	reportCount, err := CountReportsByStatus(db.StatusPending, []string{prefix + "-report-old"})
	g.Expect(err).To(gomega.Succeed())
	g.Expect(reportCount).To(gomega.BeNumerically(">=", 1))
	reportBatch, err := SelectReportByStatusBatch(db.StatusPending, 1, []string{prefix + "-report-old"})
	g.Expect(err).To(gomega.Succeed())
	g.Expect(reportBatch).To(gomega.HaveLen(1))
	g.Expect(reportBatch[0].UUID).To(gomega.Equal(prefix + "-report-new"))
}

func newHealthReportBatchRecord(fileUUID string, status db.StatusType, createdAt time.Time) *db.HealthReport {
	return &db.HealthReport{
		Model: gorm.Model{
			CreatedAt: createdAt,
		},
		FileUUID: fileUUID,
		Status:   string(status),
		OrgType:  "cloud",
	}
}

func newComparisonReportBatchRecord(hash string, status db.StatusType, createdAt time.Time) *db.ComparisonReport {
	return &db.ComparisonReport{
		Model: gorm.Model{
			CreatedAt: createdAt,
		},
		ClusterID: "cluster-" + hash,
		OrgID:     1,
		OrgType:   "cloud",
		Hash:      hash,
		Status:    string(status),
		Creator:   "test",
	}
}

func newReportBatchRecord(uuid string, status db.StatusType, createdAt time.Time) *db.Report {
	return &db.Report{
		Model: gorm.Model{
			CreatedAt: createdAt,
		},
		UUID:       uuid,
		OrgID:      1,
		ClusterID:  "cluster-" + uuid,
		ReportType: "health",
		Status:     string(status),
	}
}
