package cluster

import (
	"time"

	"github.com/pingcap/dbaas/central/db"
	"github.com/pingcap/dbaas/central/db/entity"
	"github.com/pingcap/log"
	"github.com/prometheus/client_golang/prometheus"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

var ClusterCreateCount = prometheus.NewDesc(
	prometheus.BuildFQName("dbaas", "tidb_cluster", "create_total"),
	"The execution status count of creating cluster",
	[]string{"status", "dev_tier"},
	nil)

const creationTimeout = 20 * time.Minute

type StatusCollector struct{}

func NewClusterStatusCollector() prometheus.Collector {
	return &StatusCollector{}
}

func (c *StatusCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- ClusterCreateCount
}

func (c *StatusCollector) Collect(ch chan<- prometheus.Metric) {
	var (
		clusters    []entity.Cluster
		devTierSucc float64
		devTierFail float64
		legacySucc  float64
		legacyFail  float64
	)
	log.Info("cluster status collector collect status")
	todayTime := time.Now().Truncate(24 * time.Hour)
	err := db.Transaction(func(tx *gorm.DB) error {
		return entity.NewClusterQuerySet(tx).CreatedAtGte(todayTime).PreloadTenant().All(&clusters)
	})
	if err != nil {
		log.Error("cluster status collector get cluster error", zap.Error(err))
		return
	}

	for _, cluster := range clusters {
		isDevTier := cluster.Free
		if isDevTier && cluster.Tenant.Kind == entity.TenantKindInternal {
			continue
		}
		var succ bool
		if !cluster.Status.Creating() {
			if cluster.CreationFinishedTime != nil {
				if cluster.CreationFinishedTime.Sub(cluster.CreatedAt) > creationTimeout {
					succ = false
				} else {
					succ = true
				}
			}
		} else if time.Since(cluster.CreatedAt) > creationTimeout {
			succ = false
		}

		if succ {
			if isDevTier {
				devTierSucc += 1
			} else {
				legacySucc += 1
			}
		} else {
			if isDevTier {
				devTierFail += 1
			} else {
				legacyFail += 1
			}
		}
	}
	ch <- prometheus.MustNewConstMetric(
		ClusterCreateCount,
		prometheus.CounterValue,
		devTierSucc,
		"ok",
		"true",
	)
	ch <- prometheus.MustNewConstMetric(
		ClusterCreateCount,
		prometheus.CounterValue,
		devTierFail,
		"fail",
		"true",
	)
	ch <- prometheus.MustNewConstMetric(
		ClusterCreateCount,
		prometheus.CounterValue,
		legacySucc,
		"ok",
		"false",
	)
	ch <- prometheus.MustNewConstMetric(
		ClusterCreateCount,
		prometheus.CounterValue,
		legacyFail,
		"fail",
		"false",
	)
}
