package cluster

import (
	"fmt"
	"testing"
	"time"

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

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

func TestResolveDashboardContextCompatibility(t *testing.T) {
	const start, end uint64 = 1788849000, 1788849600
	tests := []struct {
		name           string
		orgType        string
		deployType     string
		clusterName    string
		fileName       string
		upload         bool
		outsideRange   bool
		incomplete     bool
		noTimeRange    bool
		wantSuffix     string
		wantK8sCluster string
		wantCloud      bool
	}{
		{name: "operator package name", deployType: "tidb-operator", clusterName: "old/old-eks", upload: true, fileName: "new/new-eks", wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=new-eks"},
		{name: "operator empty package name", deployType: "tidb-operator", clusterName: "shop/shop-eks", upload: true, wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=shop-eks"},
		{name: "operator without package", deployType: "tidb-operator", clusterName: "shop/shop-eks", wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=shop-eks"},
		{name: "operator outside upload range", deployType: "tidb-operator", clusterName: "shop/shop-eks", upload: true, fileName: "stale/stale-eks", outsideRange: true, wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=shop-eks"},
		{name: "operator incomplete upload", deployType: "tidb-operator", clusterName: "shop/shop-eks", upload: true, fileName: "pending/pending-eks", incomplete: true, wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=shop-eks"},
		{name: "operator without time range", deployType: "tidb-operator", clusterName: "shop/shop-eks", upload: true, fileName: "new/new-eks", noTimeRange: true, wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=shop-eks"},
		{name: "operator without names", deployType: "tidb-operator", upload: true, wantSuffix: "operator"},
		{name: "operator URL encoding", deployType: "tidb-operator", upload: true, fileName: "namespace/eks & blue", wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=eks+%26+blue"},
		{name: "tiup with package", deployType: "tiup-cluster", clusterName: "cdc-test", upload: true, fileName: "cdc-test", wantSuffix: "cluster"},
		{name: "tiup without package", deployType: "tiup-cluster", clusterName: "cdc-test", wantSuffix: "cluster"},
		{name: "unknown deployment with package", upload: true, fileName: "namespace/eks", wantSuffix: "cluster"},
		{name: "cloud uploaded metrics", orgType: "cloud", deployType: o11y.DedicatedType, upload: true, fileName: "uploaded/uploaded-eks", wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=uploaded-eks"},
		{name: "cloud upload name fallback", orgType: "cloud", deployType: o11y.DedicatedType, clusterName: "cluster/cluster-eks", upload: true, wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=cluster-eks"},
		{name: "cloud premium uploaded metrics", orgType: "cloud", deployType: o11y.PremiumType, upload: true, fileName: "uploaded/uploaded-eks", wantSuffix: "operator", wantK8sCluster: "&var-k8s_cluster=uploaded-eks"},
		{name: "cloud dedicated online", orgType: "cloud", deployType: o11y.DedicatedType, wantSuffix: "tidbcloud", wantCloud: true},
		{name: "cloud premium online", orgType: "cloud", deployType: o11y.PremiumType, wantSuffix: "nextgen", wantCloud: true},
		{name: "cloud outside upload range", orgType: "cloud", deployType: o11y.DedicatedType, upload: true, fileName: "stale/stale-eks", outsideRange: true, wantSuffix: "tidbcloud", wantCloud: true},
	}

	for i, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			g := gomega.NewWithT(t)
			clusterID := fmt.Sprintf("dashboard-context-%d", i)
			org := &db.Organization{Model: gorm.Model{ID: 1}, OrgType: tt.orgType}
			cluster := &db.Cluster{ClusterID: clusterID, DeployType: tt.deployType, Name: tt.clusterName}
			if tt.upload {
				beginTime, endTime := time.Unix(int64(start), 0), time.Unix(int64(end), 0)
				if tt.outsideRange {
					beginTime, endTime = beginTime.Add(-time.Hour), endTime.Add(-time.Hour)
				}
				file := &db.UploadFile{
					FileUUID: clusterID, OrgID: org.ID, ClusterID: clusterID, ClusterName: tt.fileName,
					BeginTime: &beginTime, EndTime: &endTime, UploadStatus: string(db.StatusSuccess),
				}
				if tt.incomplete {
					file.UploadStatus = "running"
				}
				g.Expect(model.InsertUploadFile(file)).To(gomega.Succeed())
				t.Cleanup(func() {
					g.Expect(db.Transaction(func(tx *gorm.DB) error {
						return tx.Unscoped().Where("file_uuid = ?", clusterID).Delete(&db.UploadFile{}).Error
					})).To(gomega.Succeed())
				})
			}

			startTime, endTime := start, end
			if tt.noTimeRange {
				startTime, endTime = 0, 0
			}
			ctx := service.resolveDashboardContext(org, cluster, clusterID, startTime, endTime)
			g.Expect(ctx.deployTypeSuffix).To(gomega.Equal(tt.wantSuffix))
			g.Expect(ctx.k8sCluster).To(gomega.Equal(tt.wantK8sCluster))
			g.Expect(ctx.useCloudDashboard).To(gomega.Equal(tt.wantCloud))
			if tt.wantCloud {
				g.Expect(ctx.orgType).To(gomega.Equal("&var-org_type=cloud"))
				g.Expect(ctx.startTime).To(gomega.Equal("now-2h"))
				g.Expect(ctx.endTime).To(gomega.Equal("now"))
			} else {
				g.Expect(ctx.orgType).To(gomega.BeEmpty())
				g.Expect(ctx.startTime).To(gomega.Equal(fmt.Sprintf("%d", startTime*1000)))
				g.Expect(ctx.endTime).To(gomega.Equal(fmt.Sprintf("%d", endTime*1000)))
			}
		})
	}
}
